]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Merge branch 'upstream'
authorBen Hutchings <ben@decadent.org.uk>
Wed, 14 Jul 2010 02:16:17 +0000 (03:16 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Wed, 14 Jul 2010 02:16:17 +0000 (03:16 +0100)
Conflicts:
Makefile.in
aclocal.m4
aclocal/ltversion.m4
compile
config.guess
config.sub
configure
linux-nfs/Makefile.in
ltmain.sh
support/Makefile.in
support/export/Makefile.in
support/include/Makefile.in
support/include/config.h.in
support/include/nfs/Makefile.in
support/include/rpcsvc/Makefile.in
support/include/sys/Makefile.in
support/include/sys/fs/Makefile.in
support/misc/Makefile.in
support/nfs/Makefile.in
tools/Makefile.in
tools/locktest/Makefile.in
tools/nlmtest/Makefile.in
tools/rpcdebug/Makefile.in
tools/rpcgen/Makefile.in
utils/Makefile.in
utils/exportfs/Makefile.in
utils/gssd/Makefile.in
utils/idmapd/Makefile.in
utils/mount/Makefile.in
utils/mountd/Makefile.in
utils/nfsd/Makefile.in
utils/nfsstat/Makefile.in
utils/showmount/Makefile.in
utils/statd/Makefile.in

129 files changed:
.gitignore
Makefile.am
Makefile.in
aclocal.m4
aclocal/ipv6.m4
aclocal/libcap.m4 [new file with mode: 0644]
aclocal/ltversion.m4
compile
config.guess
config.sub
configure
configure.ac
linux-nfs/Makefile.in
ltmain.sh
support/Makefile.am
support/Makefile.in
support/export/Makefile.in
support/export/client.c
support/export/export.c
support/export/xtab.c
support/include/Makefile.am
support/include/Makefile.in
support/include/config.h.in
support/include/exportfs.h
support/include/ha-callout.h
support/include/nfs/Makefile.in
support/include/nfs/export.h
support/include/nfs/nfs.h
support/include/nfsrpc.h
support/include/nsm.h [new file with mode: 0644]
support/include/rpcmisc.h
support/include/rpcsvc/Makefile.in
support/include/sockaddr.h [new file with mode: 0644]
support/include/sys/Makefile.in
support/include/sys/fs/Makefile.in
support/include/tcpwrapper.h
support/include/v4root.h [new file with mode: 0644]
support/misc/Makefile.in
support/misc/from_local.c
support/misc/tcpwrapper.c
support/nfs/Makefile.am
support/nfs/Makefile.in
support/nfs/cacheio.c
support/nfs/exports.c
support/nfs/getport.c
support/nfs/rmtab.c
support/nfs/rpc_socket.c
support/nfs/svc_create.c [new file with mode: 0644]
support/nfs/xio.c
support/nsm/Makefile.am [new file with mode: 0644]
support/nsm/Makefile.in [new file with mode: 0644]
support/nsm/file.c [new file with mode: 0644]
support/nsm/rpc.c [new file with mode: 0644]
support/nsm/sm_inter.x [new file with mode: 0644]
tests/Makefile.am [new file with mode: 0644]
tests/Makefile.in [new file with mode: 0644]
tests/nsm_client/Makefile.am [new file with mode: 0644]
tests/nsm_client/Makefile.in [new file with mode: 0644]
tests/nsm_client/README [new file with mode: 0644]
tests/nsm_client/nlm_sm_inter.x [new file with mode: 0644]
tests/nsm_client/nsm_client.c [new file with mode: 0644]
tests/statdb_dump.c [new file with mode: 0644]
tests/t0001-statd-basic-mon-unmon.sh [new file with mode: 0644]
tests/test-lib.sh [new file with mode: 0644]
tools/Makefile.in
tools/locktest/Makefile.in
tools/nlmtest/Makefile.in
tools/rpcdebug/Makefile.in
tools/rpcgen/Makefile.in
utils/Makefile.in
utils/exportfs/Makefile.in
utils/exportfs/exportfs.c
utils/gssd/Makefile.in
utils/gssd/gssd.c
utils/gssd/gssd.h
utils/gssd/gssd_main_loop.c
utils/gssd/gssd_proc.c
utils/gssd/krb5_util.c
utils/gssd/krb5_util.h
utils/gssd/svcgssd_proc.c
utils/idmapd/Makefile.am
utils/idmapd/Makefile.in
utils/idmapd/idmapd.conf.man [deleted file]
utils/mount/Makefile.in
utils/mount/configfile.c
utils/mount/mount.c
utils/mount/network.c
utils/mount/network.h
utils/mount/nfs.man
utils/mount/nfs4mount.c
utils/mount/nfsmount.c
utils/mount/nfsumount.c
utils/mount/stropts.c
utils/mountd/Makefile.am
utils/mountd/Makefile.in
utils/mountd/auth.c
utils/mountd/cache.c
utils/mountd/mount_dispatch.c
utils/mountd/mountd.c
utils/mountd/rmtab.c
utils/mountd/v4root.c [new file with mode: 0644]
utils/nfsd/Makefile.in
utils/nfsd/nfssvc.c
utils/nfsstat/Makefile.in
utils/nfsstat/nfsstat.c
utils/showmount/Makefile.in
utils/showmount/showmount.c
utils/statd/Makefile.am
utils/statd/Makefile.in
utils/statd/callback.c
utils/statd/hostname.c [new file with mode: 0644]
utils/statd/log.c [deleted file]
utils/statd/log.h [deleted file]
utils/statd/misc.c
utils/statd/monitor.c
utils/statd/notlist.c
utils/statd/notlist.h
utils/statd/rmtcall.c
utils/statd/simu.c
utils/statd/simulate.c
utils/statd/sm-notify.c
utils/statd/sm-notify.man
utils/statd/sm_inter.x [deleted file]
utils/statd/stat.c
utils/statd/statd.c
utils/statd/statd.h
utils/statd/statd.man
utils/statd/svc_run.c
utils/statd/version.h [deleted file]

index 632609e3f3ada4a488d1680862685c65bcf43998..4bff9e382a27e1c3855126fbdf430a7fc1290e72 100644 (file)
@@ -55,10 +55,15 @@ support/export/mount.h
 support/export/mount_clnt.c
 support/export/mount_xdr.c
 support/include/mount.h
-utils/statd/sm_inter.h
-utils/statd/sm_inter_clnt.c
-utils/statd/sm_inter_svc.c
-utils/statd/sm_inter_xdr.c
+support/nsm/sm_inter.h
+support/nsm/sm_inter_clnt.c
+support/nsm/sm_inter_svc.c
+support/nsm/sm_inter_xdr.c
+support/include/sm_inter.h
+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
 # cscope database files
 cscope.*
 # generic editor backup et al
index b3a6e912b6575ae5f51f252496978ad461c658f3..ae7cd16519648d2664958fc4de6483bf6bd266d2 100644 (file)
@@ -2,7 +2,7 @@
 
 AUTOMAKE_OPTIONS = foreign
 
-SUBDIRS = tools support utils linux-nfs
+SUBDIRS = tools support utils linux-nfs tests
 
 MAINTAINERCLEANFILES = Makefile.in
 
index 95eb3c702b57a3ae2c48b804133c881ecd77d1b5..5d2f7464358725bd8f4e33eaaf5caf659c09fd7a 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -43,6 +43,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -169,6 +170,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -235,6 +237,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -271,7 +274,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 AUTOMAKE_OPTIONS = foreign
-SUBDIRS = tools support utils linux-nfs
+SUBDIRS = tools support utils linux-nfs tests
 MAINTAINERCLEANFILES = Makefile.in
 EXTRA_DIST = \
        autogen.sh \
@@ -368,7 +371,7 @@ distclean-libtool:
 #     (which will cause the Makefiles to be regenerated when you run `make');
 # (2) otherwise, pass the desired values on the `make' command line.
 $(RECURSIVE_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -393,7 +396,7 @@ $(RECURSIVE_TARGETS):
        fi; test -z "$$fail"
 
 $(RECURSIVE_CLEAN_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -557,7 +560,8 @@ distdir: $(DISTFILES)
          fi; \
        done
        -test -n "$(am__skip_mode_fix)" \
-       || find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+       || find "$(distdir)" -type d ! -perm -755 \
+               -exec chmod u+rwx,go+rx {} \; -o \
          ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
          ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
          ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
@@ -601,17 +605,17 @@ dist dist-all: distdir
 distcheck: dist
        case '$(DIST_ARCHIVES)' in \
        *.tar.gz*) \
-         GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+         GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
        *.tar.bz2*) \
-         bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+         bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
        *.tar.lzma*) \
-         unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+         lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
        *.tar.xz*) \
          xz -dc $(distdir).tar.xz | $(am__untar) ;;\
        *.tar.Z*) \
          uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
        *.shar.gz*) \
-         GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+         GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
        *.zip*) \
          unzip $(distdir).zip ;;\
        esac
index 8c8ee96cf7b67ded125abb1ce0415f8772e3fdfd..45e277ca3ca542242bc286b73900588b41bb8d65 100644 (file)
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.11 -*- Autoconf -*-
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 # 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
@@ -7862,15 +7862,15 @@ m4_define([lt_dict_filter],
 
 # Generated from ltversion.in.
 
-# serial 3012 ltversion.m4
+# serial 3017 ltversion.m4
 # This file is part of GNU Libtool
 
-m4_define([LT_PACKAGE_VERSION], [2.2.6])
-m4_define([LT_PACKAGE_REVISION], [1.3012])
+m4_define([LT_PACKAGE_VERSION], [2.2.6b])
+m4_define([LT_PACKAGE_REVISION], [1.3017])
 
 AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.2.6'
-macro_revision='1.3012'
+[macro_version='2.2.6b'
+macro_revision='1.3017'
 _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
 _LT_DECL(, macro_revision, 0)
 ])
@@ -8139,7 +8139,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
 [am__api_version='1.11'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.11], [],
+m4_if([$1], [1.11.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -8155,7 +8155,7 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.11])dnl
+[AM_AUTOMAKE_VERSION([1.11.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
@@ -9133,6 +9133,7 @@ m4_include([aclocal/bsdsignals.m4])
 m4_include([aclocal/ipv6.m4])
 m4_include([aclocal/kerberos5.m4])
 m4_include([aclocal/libblkid.m4])
+m4_include([aclocal/libcap.m4])
 m4_include([aclocal/libevent.m4])
 m4_include([aclocal/libnfsidmap.m4])
 m4_include([aclocal/librpcsecgss.m4])
index 2490f3d0ea4e5567d5ae38441d04b277b374605a..5ee8fb6e85f1c54e39d2c1016b0b0abfb2aa7ea6 100644 (file)
@@ -15,8 +15,8 @@ AC_DEFUN([AC_IPV6], [
     fi
 
     dnl IPv6-enabled networking functions required for IPv6
-    AC_CHECK_FUNCS([getnameinfo bindresvport_sa], ,
-                   [AC_MSG_ERROR([Missing functions needed for IPv6.])])
+    AC_CHECK_FUNCS([getifaddrs getnameinfo bindresvport_sa], ,
+                   [AC_MSG_ERROR([Missing library functions needed for IPv6.])])
 
     dnl Need to detect presence of IPv6 networking at run time via
     dnl getaddrinfo(3); old versions of glibc do not support ADDRCONFIG
diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4
new file mode 100644 (file)
index 0000000..eabe507
--- /dev/null
@@ -0,0 +1,15 @@
+dnl Checks for libcap.so
+dnl
+AC_DEFUN([AC_LIBCAP], [
+
+  dnl look for prctl
+  AC_CHECK_FUNC([prctl], , )
+
+  dnl look for the library; do not add to LIBS if found
+  AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
+  AC_SUBST(LIBCAP)
+
+  AC_CHECK_HEADERS([sys/capability.h], ,
+                   [AC_MSG_ERROR([libcap headers not found.])])
+
+])dnl
index b8e154fe6e10fb20e2cf7d9e3a59116fb27cb79b..f3c5309802447a3b341b1a2c5e4d74ec138b311a 100644 (file)
@@ -9,15 +9,15 @@
 
 # Generated from ltversion.in.
 
-# serial 3012 ltversion.m4
+# serial 3017 ltversion.m4
 # This file is part of GNU Libtool
 
-m4_define([LT_PACKAGE_VERSION], [2.2.6])
-m4_define([LT_PACKAGE_REVISION], [1.3012])
+m4_define([LT_PACKAGE_VERSION], [2.2.6b])
+m4_define([LT_PACKAGE_REVISION], [1.3017])
 
 AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.2.6'
-macro_revision='1.3012'
+[macro_version='2.2.6b'
+macro_revision='1.3017'
 _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
 _LT_DECL(, macro_revision, 0)
 ])
diff --git a/compile b/compile
index ec64c6220266fb75d8c6b6e0e32492f5983f3472..c0096a7b563231c0c7ade728962574ec3b8df270 100755 (executable)
--- a/compile
+++ b/compile
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Wrapper for compilers which do not understand `-c -o'.
 
-scriptversion=2009-04-28.21; # UTC
+scriptversion=2009-10-06.20; # UTC
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009  Free Software
 # Foundation, Inc.
@@ -124,9 +124,9 @@ trap "rmdir '$lockdir'; exit 1" 1 2 15
 ret=$?
 
 if test -f "$cofile"; then
-  mv "$cofile" "$ofile"
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
 elif test -f "${cofile}bj"; then
-  mv "${cofile}bj" "$ofile"
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
 fi
 
 rmdir "$lockdir"
index da8331460888af3b367e2a9df88cb52022866c73..dc84c68ef798c6a5000c78c6dd7380d34c9e0218 100755 (executable)
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 #   Free Software Foundation, Inc.
 
-timestamp='2009-04-27'
+timestamp='2009-11-20'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -27,16 +27,16 @@ timestamp='2009-04-27'
 # the same distribution terms that you use for the rest of that program.
 
 
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>.  Submit a context
-# diff and a properly formatted ChangeLog entry.
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
 #
 # This script attempts to guess a canonical system name similar to
 # config.sub.  If it succeeds, it prints the system name on stdout, and
 # exits with 0.  Otherwise, it exits with 1.
 #
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
 
 me=`echo "$0" | sed -e 's,.*/,,'`
 
@@ -170,7 +170,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
            arm*|i386|m68k|ns32k|sh3*|sparc|vax)
                eval $set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
-                       | grep __ELF__ >/dev/null
+                       | grep -q __ELF__
                then
                    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
                    # Return netbsd for either.  FIX?
@@ -333,6 +333,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
        echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
        exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
        eval $set_cc_for_build
        SUN_ARCH="i386"
@@ -656,7 +659,7 @@ EOF
            # => hppa64-hp-hpux11.23
 
            if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
-               grep __LP64__ >/dev/null
+               grep -q __LP64__
            then
                HP_ARCH="hppa2.0w"
            else
@@ -807,12 +810,12 @@ EOF
     i*:PW*:*)
        echo ${UNAME_MACHINE}-pc-pw32
        exit ;;
-    *:Interix*:[3456]*)
+    *:Interix*:*)
        case ${UNAME_MACHINE} in
            x86)
                echo i586-pc-interix${UNAME_RELEASE}
                exit ;;
-           EM64T | authenticamd | genuineintel)
+           authenticamd | genuineintel | EM64T)
                echo x86_64-unknown-interix${UNAME_RELEASE}
                exit ;;
            IA64)
@@ -822,6 +825,9 @@ EOF
     [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
        echo i${UNAME_MACHINE}-pc-mks
        exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
     i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
        # How do we know it's Interix rather than the generic POSIX subsystem?
        # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -851,6 +857,20 @@ EOF
     i*86:Minix:*:*)
        echo ${UNAME_MACHINE}-pc-minix
        exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit ;;
     arm*:Linux:*:*)
        eval $set_cc_for_build
        if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
@@ -873,6 +893,17 @@ EOF
     frv:Linux:*:*)
        echo frv-unknown-linux-gnu
        exit ;;
+    i*86:Linux:*:*)
+       LIBC=gnu
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+       echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+       exit ;;
     ia64:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit ;;
@@ -882,78 +913,34 @@ EOF
     m68*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit ;;
-    mips:Linux:*:*)
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-       #undef CPU
-       #undef mips
-       #undef mipsel
-       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-       CPU=mipsel
-       #else
-       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-       CPU=mips
-       #else
-       CPU=
-       #endif
-       #endif
-EOF
-       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-           /^CPU/{
-               s: ::g
-               p
-           }'`"
-       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
-       ;;
-    mips64:Linux:*:*)
+    mips:Linux:*:* | mips64:Linux:*:*)
        eval $set_cc_for_build
        sed 's/^        //' << EOF >$dummy.c
        #undef CPU
-       #undef mips64
-       #undef mips64el
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
        #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-       CPU=mips64el
+       CPU=${UNAME_MACHINE}el
        #else
        #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-       CPU=mips64
+       CPU=${UNAME_MACHINE}
        #else
        CPU=
        #endif
        #endif
 EOF
-       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-           /^CPU/{
-               s: ::g
-               p
-           }'`"
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
        test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
        ;;
     or32:Linux:*:*)
        echo or32-unknown-linux-gnu
        exit ;;
-    ppc:Linux:*:*)
-       echo powerpc-unknown-linux-gnu
-       exit ;;
-    ppc64:Linux:*:*)
-       echo powerpc64-unknown-linux-gnu
-       exit ;;
-    alpha:Linux:*:*)
-       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
-         EV5)   UNAME_MACHINE=alphaev5 ;;
-         EV56)  UNAME_MACHINE=alphaev56 ;;
-         PCA56) UNAME_MACHINE=alphapca56 ;;
-         PCA57) UNAME_MACHINE=alphapca56 ;;
-         EV6)   UNAME_MACHINE=alphaev6 ;;
-         EV67)  UNAME_MACHINE=alphaev67 ;;
-         EV68*) UNAME_MACHINE=alphaev68 ;;
-        esac
-       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
-       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
-       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
-       exit ;;
     padre:Linux:*:*)
        echo sparc-unknown-linux-gnu
        exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
        # Look for CPU level
        case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
@@ -962,8 +949,11 @@ EOF
          *)    echo hppa-unknown-linux-gnu ;;
        esac
        exit ;;
-    parisc64:Linux:*:* | hppa64:Linux:*:*)
-       echo hppa64-unknown-linux-gnu
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
        exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
        echo ${UNAME_MACHINE}-ibm-linux
@@ -986,66 +976,6 @@ EOF
     xtensa*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit ;;
-    i*86:Linux:*:*)
-       # The BFD linker knows what the default object file format is, so
-       # first see if it will tell us. cd to the root directory to prevent
-       # problems with other programs or directories called `ld' in the path.
-       # Set LC_ALL=C to ensure ld outputs messages in English.
-       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
-                        | sed -ne '/supported targets:/!d
-                                   s/[         ][      ]*/ /g
-                                   s/.*supported targets: *//
-                                   s/ .*//
-                                   p'`
-        case "$ld_supported_targets" in
-         elf32-i386)
-               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
-               ;;
-         a.out-i386-linux)
-               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
-               exit ;;
-         "")
-               # Either a pre-BFD a.out linker (linux-gnuoldld) or
-               # one that does not give us useful --help.
-               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
-               exit ;;
-       esac
-       # Determine whether the default compiler is a.out or elf
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-       #include <features.h>
-       #ifdef __ELF__
-       # ifdef __GLIBC__
-       #  if __GLIBC__ >= 2
-       LIBC=gnu
-       #  else
-       LIBC=gnulibc1
-       #  endif
-       # else
-       LIBC=gnulibc1
-       # endif
-       #else
-       #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-       LIBC=gnu
-       #else
-       LIBC=gnuaout
-       #endif
-       #endif
-       #ifdef __dietlibc__
-       LIBC=dietlibc
-       #endif
-EOF
-       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-           /^LIBC/{
-               s: ::g
-               p
-           }'`"
-       test x"${LIBC}" != x && {
-               echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
-               exit
-       }
-       test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
-       ;;
     i*86:DYNIX/ptx:4*:*)
        # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
        # earlier versions are messed up and put the nodename in both
@@ -1074,7 +1004,7 @@ EOF
     i*86:syllable:*:*)
        echo ${UNAME_MACHINE}-pc-syllable
        exit ;;
-    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
        echo i386-unknown-lynxos${UNAME_RELEASE}
        exit ;;
     i*86:*DOS:*:*)
@@ -1182,7 +1112,7 @@ EOF
     rs6000:LynxOS:2.*:*)
        echo rs6000-unknown-lynxos${UNAME_RELEASE}
        exit ;;
-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
        echo powerpc-unknown-lynxos${UNAME_RELEASE}
        exit ;;
     SM[BE]S:UNIX_SV:*:*)
@@ -1275,6 +1205,16 @@ EOF
     *:Darwin:*:*)
        UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
        case $UNAME_PROCESSOR in
+           i386)
+               eval $set_cc_for_build
+               if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+                 if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                     (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                     grep IS_64BIT_ARCH >/dev/null
+                 then
+                     UNAME_PROCESSOR="x86_64"
+                 fi
+               fi ;;
            unknown) UNAME_PROCESSOR=powerpc ;;
        esac
        echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
index a39437d0158ed7058a189617db490472252a70ae..2a55a50751c1aaf99de876b404ed613005dfcce1 100755 (executable)
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Configuration validation subroutine script.
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 #   Free Software Foundation, Inc.
 
-timestamp='2009-04-17'
+timestamp='2009-11-20'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
@@ -32,13 +32,16 @@ timestamp='2009-04-17'
 
 
 # Please send patches to <config-patches@gnu.org>.  Submit a context
-# diff and a properly formatted ChangeLog entry.
+# diff and a properly formatted GNU ChangeLog entry.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
 # If it is invalid, we print an error message on stderr and exit with code 1.
 # Otherwise, we print the canonical config type on stdout and succeed.
 
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
 # that are meaningful with *any* GNU software.
@@ -149,10 +152,13 @@ case $os in
        -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
        -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
        -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-       -apple | -axis | -knuth | -cray)
+       -apple | -axis | -knuth | -cray | -microblaze)
                os=
                basic_machine=$1
                ;;
+        -bluegene*)
+               os=-cnk
+               ;;
        -sim | -cisco | -oki | -wec | -winbond)
                os=
                basic_machine=$1
@@ -281,6 +287,7 @@ case $basic_machine in
        | pdp10 | pdp11 | pj | pjl \
        | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
        | pyramid \
+       | rx \
        | score \
        | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
        | sh64 | sh64le \
@@ -288,13 +295,14 @@ case $basic_machine in
        | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
        | spu | strongarm \
        | tahoe | thumb | tic4x | tic80 | tron \
+       | ubicom32 \
        | v850 | v850e \
        | we32k \
        | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
        | z8k | z80)
                basic_machine=$basic_machine-unknown
                ;;
-       m6811 | m68hc11 | m6812 | m68hc12)
+       m6811 | m68hc11 | m6812 | m68hc12 | picochip)
                # Motorola 68HC11/12.
                basic_machine=$basic_machine-unknown
                os=-none
@@ -337,7 +345,7 @@ case $basic_machine in
        | lm32-* \
        | m32c-* | m32r-* | m32rle-* \
        | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
        | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
        | mips16-* \
        | mips64-* | mips64el-* \
@@ -365,7 +373,7 @@ case $basic_machine in
        | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
        | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
        | pyramid-* \
-       | romp-* | rs6000-* \
+       | romp-* | rs6000-* | rx-* \
        | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
        | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
        | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
@@ -374,6 +382,7 @@ case $basic_machine in
        | tahoe-* | thumb-* \
        | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
        | tron-* \
+       | ubicom32-* \
        | v850-* | v850e-* | vax-* \
        | we32k-* \
        | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
@@ -467,6 +476,10 @@ case $basic_machine in
                basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
                os=-linux
                ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
        c90)
                basic_machine=c90-cray
                os=-unicos
@@ -719,6 +732,9 @@ case $basic_machine in
                basic_machine=ns32k-utek
                os=-sysv
                ;;
+        microblaze)
+               basic_machine=microblaze-xilinx
+               ;;
        mingw32)
                basic_machine=i386-pc
                os=-mingw32
@@ -1240,6 +1256,9 @@ case $os in
         # First match some system type aliases
         # that might get confused with valid system types.
        # -solaris* is a basic system type, with this one exception.
+        -auroraux)
+               os=-auroraux
+               ;;
        -solaris1 | -solaris1.*)
                os=`echo $os | sed -e 's|solaris1|sunos4|'`
                ;;
@@ -1260,9 +1279,9 @@ case $os in
        # Each alternative MUST END IN A *, to match a version number.
        # -sysv* is not here because it comes later, after sysvr4.
        -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
-             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
-             | -kopensolaris* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* \
              | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
              | -aos* | -aros* \
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
@@ -1283,7 +1302,7 @@ case $os in
              | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
              | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
              | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-             | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
@@ -1613,7 +1632,7 @@ case $basic_machine in
                        -sunos*)
                                vendor=sun
                                ;;
-                       -aix*)
+                       -cnk*|-aix*)
                                vendor=ibm
                                ;;
                        -beos*)
index 926d7359e2161cddad197bf2dddbe2dc3f6561ea..0080be3772600bacf32383512688667ca9e5add2 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for linux nfs-utils 1.2.1.
+# Generated by GNU Autoconf 2.63 for linux nfs-utils 1.2.2.
 #
 # Report bugs to <linux-nfs@vger.kernel.org>.
 #
@@ -745,8 +745,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='linux nfs-utils'
 PACKAGE_TARNAME='nfs-utils'
-PACKAGE_VERSION='1.2.1'
-PACKAGE_STRING='linux nfs-utils 1.2.1'
+PACKAGE_VERSION='1.2.2'
+PACKAGE_STRING='linux nfs-utils 1.2.2'
 PACKAGE_BUGREPORT='linux-nfs@vger.kernel.org'
 
 ac_default_prefix=/usr
@@ -841,6 +841,7 @@ CXX
 HAVE_TCP_WRAPPER
 HAVE_LIBWRAP
 LIBWRAP
+LIBCAP
 EGREP
 GREP
 CPP
@@ -879,6 +880,9 @@ CONFIG_GSS_TRUE
 enable_gss
 SVCGSSD
 GSSD
+CONFIG_NFSV41_FALSE
+CONFIG_NFSV41_TRUE
+enable_nfsv41
 CONFIG_NFSV4_FALSE
 CONFIG_NFSV4_TRUE
 enable_nfsv4
@@ -969,6 +973,7 @@ with_statduser
 with_start_statd
 enable_nfsv3
 enable_nfsv4
+enable_nfsv41
 enable_gss
 enable_kprefix
 with_rpcgen
@@ -1560,7 +1565,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures linux nfs-utils 1.2.1 to adapt to many kinds of systems.
+\`configure' configures linux nfs-utils 1.2.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1630,7 +1635,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of linux nfs-utils 1.2.1:";;
+     short | recursive ) echo "Configuration of linux nfs-utils 1.2.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1642,6 +1647,7 @@ Optional Features:
                          (and sometimes confusing) to the casual installer
   --enable-nfsv3          enable support for NFSv3 [default=yes]
   --enable-nfsv4          enable support for NFSv4 [default=yes]
+  --enable-nfsv41         enable support for NFSv41 [default=no]
   --enable-gss            enable support for rpcsec_gss [default=yes]
   --enable-kprefix        install progs as rpc.knfsd etc
   --disable-uuid          Exclude uuid support to avoid buggy libblkid
@@ -1769,7 +1775,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-linux nfs-utils configure 1.2.1
+linux nfs-utils configure 1.2.2
 generated by GNU Autoconf 2.63
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1783,7 +1789,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by linux nfs-utils $as_me 1.2.1, which was
+It was created by linux nfs-utils $as_me 1.2.2, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   $ $0 $@
@@ -2716,7 +2722,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='nfs-utils'
- VERSION='1.2.1'
+ VERSION='1.2.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2877,6 +2883,33 @@ else
   CONFIG_NFSV4_FALSE=
 fi
 
+
+# Check whether --enable-nfsv41 was given.
+if test "${enable_nfsv41+set}" = set; then
+  enableval=$enable_nfsv41; enable_nfsv41=$enableval
+else
+  enable_nfsv41=no
+fi
+
+       if test "$enable_nfsv41" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NFS41_SUPPORTED 1
+_ACEOF
+
+       else
+               enable_nfsv4=
+       fi
+
+        if test "$enable_nfsv41" = "yes"; then
+  CONFIG_NFSV41_TRUE=
+  CONFIG_NFSV41_FALSE='#'
+else
+  CONFIG_NFSV41_TRUE='#'
+  CONFIG_NFSV41_FALSE=
+fi
+
+
 # Check whether --enable-gss was given.
 if test "${enable_gss+set}" = set; then
   enableval=$enable_gss; enable_gss=$enableval
@@ -5060,6 +5093,324 @@ done
 
 
 
+
+
+    { $as_echo "$as_me:$LINENO: checking for prctl" >&5
+$as_echo_n "checking for prctl... " >&6; }
+if test "${ac_cv_func_prctl+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define prctl to an innocuous variant, in case <limits.h> declares prctl.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define prctl innocuous_prctl
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char prctl (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef prctl
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char prctl ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_prctl || defined __stub___prctl
+choke me
+#endif
+
+int
+main ()
+{
+return prctl ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_prctl=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_prctl=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_prctl" >&5
+$as_echo "$ac_cv_func_prctl" >&6; }
+
+
+    { $as_echo "$as_me:$LINENO: checking for cap_get_proc in -lcap" >&5
+$as_echo_n "checking for cap_get_proc in -lcap... " >&6; }
+if test "${ac_cv_lib_cap_cap_get_proc+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcap  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cap_get_proc ();
+int
+main ()
+{
+return cap_get_proc ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_cap_cap_get_proc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_cap_cap_get_proc=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_get_proc" >&5
+$as_echo "$ac_cv_lib_cap_cap_get_proc" >&6; }
+if test "x$ac_cv_lib_cap_cap_get_proc" = x""yes; then
+  LIBCAP=-lcap
+fi
+
+
+
+
+for ac_header in sys/capability.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ---------------------------------------- ##
+## Report this to linux-nfs@vger.kernel.org ##
+## ---------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { $as_echo "$as_me:$LINENO: error: libcap headers not found." >&5
+$as_echo "$as_me: error: libcap headers not found." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+done
+
+
+
+
 # Check whether user wants TCP wrappers support
 
   TCPW_MSG="no"
@@ -7232,8 +7583,8 @@ esac
 
 
 
-macro_version='2.2.6'
-macro_revision='1.3012'
+macro_version='2.2.6b'
+macro_revision='1.3017'
 
 
 
@@ -7709,13 +8060,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
 else
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:7712: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:8063: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:7715: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:8066: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:7718: output\"" >&5)
+  (eval echo "\"\$as_me:8069: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -8909,7 +9260,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 8912 "configure"' > conftest.$ac_ext
+  echo '#line 9263 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -11012,11 +11363,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11015: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11366: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:11019: \$? = $ac_status" >&5
+   echo "$as_me:11370: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -11351,11 +11702,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11354: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11705: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:11358: \$? = $ac_status" >&5
+   echo "$as_me:11709: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -11456,11 +11807,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11459: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11810: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:11463: \$? = $ac_status" >&5
+   echo "$as_me:11814: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -11511,11 +11862,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11514: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11865: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:11518: \$? = $ac_status" >&5
+   echo "$as_me:11869: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -14314,7 +14665,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 14317 "configure"
+#line 14668 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14410,7 +14761,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 14413 "configure"
+#line 14764 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -16430,11 +16781,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16433: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16784: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:16437: \$? = $ac_status" >&5
+   echo "$as_me:16788: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -16529,11 +16880,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16532: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16883: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:16536: \$? = $ac_status" >&5
+   echo "$as_me:16887: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -16581,11 +16932,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16584: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16935: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:16588: \$? = $ac_status" >&5
+   echo "$as_me:16939: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -21455,7 +21806,8 @@ $as_echo "$as_me: error: '--enable-ipv6' requires TIRPC support." >&2;}
 
 
 
-for ac_func in getnameinfo bindresvport_sa
+
+for ac_func in getifaddrs getnameinfo bindresvport_sa
 do
 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -21553,8 +21905,8 @@ as_val=`eval 'as_val=${'$as_ac_var'}
 _ACEOF
 
 else
-  { { $as_echo "$as_me:$LINENO: error: Missing functions needed for IPv6." >&5
-$as_echo "$as_me: error: Missing functions needed for IPv6." >&2;}
+  { { $as_echo "$as_me:$LINENO: error: Missing library functions needed for IPv6." >&5
+$as_echo "$as_me: error: Missing library functions needed for IPv6." >&2;}
    { (exit 1); exit 1; }; }
 fi
 done
@@ -25528,11 +25880,12 @@ done
 
 
 
+
 
 
 for ac_func in alarm atexit dup2 fdatasync ftruncate getcwd \
                gethostbyaddr gethostbyname gethostname getmntent \
-               getnameinfo getrpcbyname \
+               getnameinfo getrpcbyname getifaddrs \
                gettimeofday hasmntopt inet_ntoa innetgr memset mkdir pathconf \
                realpath rmdir select socket strcasecmp strchr strdup \
                strerror strrchr strtol strtoul sigprocmask
@@ -27476,7 +27829,7 @@ AM_CFLAGS="$my_am_cflags"
 ACLOCAL_AMFLAGS="-I $ac_macro_dir \$(ACLOCAL_FLAGS)"
 
 
-ac_config_files="$ac_config_files Makefile linux-nfs/Makefile support/Makefile support/export/Makefile support/include/nfs/Makefile support/include/rpcsvc/Makefile support/include/sys/fs/Makefile support/include/sys/Makefile support/include/Makefile support/misc/Makefile support/nfs/Makefile tools/Makefile tools/locktest/Makefile tools/nlmtest/Makefile tools/rpcdebug/Makefile tools/rpcgen/Makefile utils/Makefile utils/exportfs/Makefile utils/gssd/Makefile utils/idmapd/Makefile utils/mount/Makefile utils/mountd/Makefile utils/nfsd/Makefile utils/nfsstat/Makefile utils/showmount/Makefile utils/statd/Makefile"
+ac_config_files="$ac_config_files Makefile linux-nfs/Makefile support/Makefile support/export/Makefile support/include/nfs/Makefile support/include/rpcsvc/Makefile support/include/sys/fs/Makefile support/include/sys/Makefile support/include/Makefile support/misc/Makefile support/nfs/Makefile support/nsm/Makefile tools/Makefile tools/locktest/Makefile tools/nlmtest/Makefile tools/rpcdebug/Makefile tools/rpcgen/Makefile utils/Makefile utils/exportfs/Makefile utils/gssd/Makefile utils/idmapd/Makefile utils/mount/Makefile utils/mountd/Makefile utils/nfsd/Makefile utils/nfsstat/Makefile utils/showmount/Makefile utils/statd/Makefile tests/Makefile tests/nsm_client/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -27597,6 +27950,13 @@ $as_echo "$as_me: error: conditional \"CONFIG_NFSV4\" was never defined.
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${CONFIG_NFSV41_TRUE}" && test -z "${CONFIG_NFSV41_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"CONFIG_NFSV41\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"CONFIG_NFSV41\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${CONFIG_GSS_TRUE}" && test -z "${CONFIG_GSS_FALSE}"; then
   { { $as_echo "$as_me:$LINENO: error: conditional \"CONFIG_GSS\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -27996,7 +28356,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by linux nfs-utils $as_me 1.2.1, which was
+This file was extended by linux nfs-utils $as_me 1.2.2, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -28059,7 +28419,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-linux nfs-utils config.status 1.2.1
+linux nfs-utils config.status 1.2.2
 configured by $0, generated by GNU Autoconf 2.63,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -28547,6 +28907,7 @@ do
     "support/include/Makefile") CONFIG_FILES="$CONFIG_FILES support/include/Makefile" ;;
     "support/misc/Makefile") CONFIG_FILES="$CONFIG_FILES support/misc/Makefile" ;;
     "support/nfs/Makefile") CONFIG_FILES="$CONFIG_FILES support/nfs/Makefile" ;;
+    "support/nsm/Makefile") CONFIG_FILES="$CONFIG_FILES support/nsm/Makefile" ;;
     "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
     "tools/locktest/Makefile") CONFIG_FILES="$CONFIG_FILES tools/locktest/Makefile" ;;
     "tools/nlmtest/Makefile") CONFIG_FILES="$CONFIG_FILES tools/nlmtest/Makefile" ;;
@@ -28562,6 +28923,8 @@ do
     "utils/nfsstat/Makefile") CONFIG_FILES="$CONFIG_FILES utils/nfsstat/Makefile" ;;
     "utils/showmount/Makefile") CONFIG_FILES="$CONFIG_FILES utils/showmount/Makefile" ;;
     "utils/statd/Makefile") CONFIG_FILES="$CONFIG_FILES utils/statd/Makefile" ;;
+    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
+    "tests/nsm_client/Makefile") CONFIG_FILES="$CONFIG_FILES tests/nsm_client/Makefile" ;;
 
   *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
 $as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
index 3ad415ca78ec7b855b74e43c127233f07e3a0d74..b7520d87810bd702a92d03fdc5fc4f891a660390 100644 (file)
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 dnl
-AC_INIT([linux nfs-utils],[1.2.1],[linux-nfs@vger.kernel.org],[nfs-utils])
+AC_INIT([linux nfs-utils],[1.2.2],[linux-nfs@vger.kernel.org],[nfs-utils])
 AC_CANONICAL_BUILD([])
 AC_CANONICAL_HOST([])
 AC_CONFIG_MACRO_DIR(aclocal)
@@ -72,6 +72,20 @@ AC_ARG_ENABLE(nfsv4,
        AC_SUBST(IDMAPD)
        AC_SUBST(enable_nfsv4)
        AM_CONDITIONAL(CONFIG_NFSV4, [test "$enable_nfsv4" = "yes"])
+
+AC_ARG_ENABLE(nfsv41,
+       [AC_HELP_STRING([--enable-nfsv41],
+                        [enable support for NFSv41 @<:@default=no@:>@])],
+       enable_nfsv41=$enableval,
+       enable_nfsv41=no)
+       if test "$enable_nfsv41" = yes; then
+               AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in])
+       else
+               enable_nfsv4=
+       fi
+       AC_SUBST(enable_nfsv41)
+       AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
+
 AC_ARG_ENABLE(gss,
        [AC_HELP_STRING([--enable-gss],
                         [enable support for rpcsec_gss @<:@default=yes@:>@])],
@@ -166,6 +180,9 @@ fi
 dnl Check for TI-RPC library and headers
 AC_LIBTIRPC
 
+dnl Check for -lcap
+AC_LIBCAP
+
 # Check whether user wants TCP wrappers support
 AC_TCP_WRAPPERS
 
@@ -327,7 +344,7 @@ AC_FUNC_STAT
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS([alarm atexit dup2 fdatasync ftruncate getcwd \
                gethostbyaddr gethostbyname gethostname getmntent \
-               getnameinfo getrpcbyname \
+               getnameinfo getrpcbyname getifaddrs \
                gettimeofday hasmntopt inet_ntoa innetgr memset mkdir pathconf \
                realpath rmdir select socket strcasecmp strchr strdup \
                strerror strrchr strtol strtoul sigprocmask])
@@ -402,6 +419,7 @@ AC_CONFIG_FILES([
        support/include/Makefile
        support/misc/Makefile
        support/nfs/Makefile
+       support/nsm/Makefile
        tools/Makefile
        tools/locktest/Makefile
        tools/nlmtest/Makefile
@@ -416,6 +434,8 @@ AC_CONFIG_FILES([
        utils/nfsd/Makefile
        utils/nfsstat/Makefile
        utils/showmount/Makefile
-       utils/statd/Makefile])
+       utils/statd/Makefile
+       tests/Makefile
+       tests/nsm_client/Makefile])
 AC_OUTPUT
 
index 3ea0b53b6ccadb68a3828e523cc631d53d741a6f..cd0f8435e39b2970a1e7c25dfc7d8bd2e90d91a1 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -41,6 +41,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -115,6 +116,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -181,6 +183,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 6939dcc4a662e3d520a779614b60eeb998bb5f7a..a72f2fd78bfc86bb35a404d1954c4ca9bb923c06 100755 (executable)
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -1,6 +1,6 @@
 # Generated from ltmain.m4sh.
 
-# ltmain.sh (GNU libtool) 2.2.6
+# ltmain.sh (GNU libtool) 2.2.6b
 # Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc.
@@ -65,7 +65,7 @@
 #       compiler:              $LTCC
 #       compiler flags:                $LTCFLAGS
 #       linker:                $LD (gnu? $with_gnu_ld)
-#       $progname:             (GNU libtool) 2.2.6
+#       $progname:             (GNU libtool) 2.2.6b
 #       automake:              $automake_version
 #       autoconf:              $autoconf_version
 #
@@ -73,9 +73,9 @@
 
 PROGRAM=ltmain.sh
 PACKAGE=libtool
-VERSION=2.2.6
+VERSION=2.2.6b
 TIMESTAMP=""
-package_revision=1.3012
+package_revision=1.3017
 
 # Be Bourne compatible
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
index aa4d692a38de596f32c412238bfb133713a20564..cb37733f9be8252bb025a5f575b9ae93daf92819 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = export include misc nfs
+SUBDIRS = export include misc nfs nsm
 
 MAINTAINERCLEANFILES = Makefile.in
 
index 6c469a03f897dfe91a6d06fcf546cdc0f72381fb..a317d462db7692c1fa0fd13243598b03bcc247fc 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -40,6 +40,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -154,6 +155,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -220,6 +222,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -255,7 +258,7 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = export include misc nfs
+SUBDIRS = export include misc nfs nsm
 MAINTAINERCLEANFILES = Makefile.in
 all: all-recursive
 
@@ -304,7 +307,7 @@ clean-libtool:
 #     (which will cause the Makefiles to be regenerated when you run `make');
 # (2) otherwise, pass the desired values on the `make' command line.
 $(RECURSIVE_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -329,7 +332,7 @@ $(RECURSIVE_TARGETS):
        fi; test -z "$$fail"
 
 $(RECURSIVE_CLEAN_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
index f2640c87dbc4382abe29ac42a76b93d56e41df59..e77cbaa1a068d773c3d6074a210c1d138d5c9dab 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -43,6 +43,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -141,6 +142,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -207,6 +209,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 5fcf35539cad917c2333d9a370f5bca6fcb7f771..6236561465f26261175b290276abeb10c39de0bd 100644 (file)
@@ -297,7 +297,7 @@ name_cmp(char *a, char *b)
        /* compare strings a and b, but only upto ',' in a */
        while (*a && *b && *a != ',' && *a == *b)
                a++, b++;
-       if (!*b && (!*a || !a == ',') )
+       if (!*b && (!*a || *a == ','))
                return 0;
        if (!*b) return 1;
        if (!*a || *a == ',') return -1;
index e5e6cb0504158447d006c8855c58e54a4e5c581e..29434660a9a01008826dd8243a17ca44b84005ba 100644 (file)
@@ -28,6 +28,22 @@ static int   export_check(nfs_export *, struct hostent *, char *);
 static nfs_export *
                export_allowed_internal(struct hostent *hp, char *path);
 
+static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
+{
+       if (exp->m_export.e_flags != eep->e_flags) {
+               xlog(L_ERROR, "incompatible duplicated export entries:");
+               xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
+                               eep->e_path, eep->e_flags);
+               xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
+                               exp->m_export.e_path, exp->m_export.e_flags);
+       } else {
+               xlog(L_ERROR, "duplicated export entries:");
+               xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
+               xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
+                               exp->m_export.e_path);
+       }
+}
+
 int
 export_read(char *fname)
 {
@@ -36,27 +52,13 @@ export_read(char *fname)
 
        setexportent(fname, "r");
        while ((eep = getexportent(0,1)) != NULL) {
-         exp = export_lookup(eep->e_hostname, eep->e_path, 0);
-         if (!exp)
-           export_create(eep,0);
-         else {
-           if (exp->m_export.e_flags != eep->e_flags) {
-             xlog(L_ERROR, "incompatible duplicated export entries:");
-             xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
-                  eep->e_path, eep->e_flags);
-             xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
-                  exp->m_export.e_path, exp->m_export.e_flags);
-           }
-           else {
-             xlog(L_ERROR, "duplicated export entries:");
-             xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
-             xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
-                  exp->m_export.e_path);
-           }
-         }
+               exp = export_lookup(eep->e_hostname, eep->e_path, 0);
+               if (!exp)
+                       export_create(eep, 0);
+               else
+                       warn_duplicated_exports(exp, eep);
        }
        endexportent();
-
        return 0;
 }
 
index 3b1dcce325493fec61fbb5385b9a89aadff8da84..2a43193c35a15345c053b005e46cf45eadabfe1b 100644 (file)
@@ -19,7 +19,9 @@
 #include "exportfs.h"
 #include "xio.h"
 #include "xlog.h"
+#include "v4root.h"
 
+int v4root_needed;
 static void cond_rename(char *newfile, char *oldfile);
 
 static int
@@ -36,6 +38,8 @@ xtab_read(char *xtab, char *lockfn, int is_export)
        if ((lockid = xflock(lockfn, "r")) < 0)
                return 0;
        setexportent(xtab, "r");
+       if (is_export == 1)
+               v4root_needed = 1;
        while ((xp = getexportent(is_export==0, 0)) != NULL) {
                if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) &&
                    !(exp = export_create(xp, is_export!=1))) {
@@ -48,6 +52,8 @@ xtab_read(char *xtab, char *lockfn, int is_export)
                case 1:
                        exp->m_xtabent = 1;
                        exp->m_mayexport = 1;
+                       if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0)
+                               v4root_needed = 0;
                        break;
                case 2:
                        exp->m_exported = -1;/* may be exported */
index f5a77ec13fd31bc776b628afb13bafa6146e245a..4b33ee92915e91cd19f3ade0d2978d5c35e0a786 100644 (file)
@@ -9,6 +9,8 @@ noinst_HEADERS = \
        nfs_mntent.h \
        nfs_paths.h \
        nfslib.h \
+       nfsrpc.h \
+       nsm.h \
        rpcmisc.h \
        tcpwrapper.h \
        xio.h \
index cff3f34adbf395ec1e34bee20a15c21ac36f6a81..5e3d74ec3a5603ca13f439d339913f0d6da90d07 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -157,6 +158,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -223,6 +225,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -266,6 +269,8 @@ noinst_HEADERS = \
        nfs_mntent.h \
        nfs_paths.h \
        nfslib.h \
+       nfsrpc.h \
+       nsm.h \
        rpcmisc.h \
        tcpwrapper.h \
        xio.h \
@@ -340,7 +345,7 @@ clean-libtool:
 #     (which will cause the Makefiles to be regenerated when you run `make');
 # (2) otherwise, pass the desired values on the `make' command line.
 $(RECURSIVE_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -365,7 +370,7 @@ $(RECURSIVE_TARGETS):
        fi; test -z "$$fail"
 
 $(RECURSIVE_CLEAN_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
index b8b46e2c9e3073f155d65ed31cab82c5bd174b49..03c9ceb8c46d27302fea7e962b4397e55b8e2760 100644 (file)
@@ -95,6 +95,9 @@
 /* Define to 1 if you have the `gethostname' function. */
 #undef HAVE_GETHOSTNAME
 
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
 /* Define to 1 if you have the `getmntent' function. */
 #undef HAVE_GETMNTENT
 
 /* Define to 1 if you have the <syslog.h> header file. */
 #undef HAVE_SYSLOG_H
 
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_H
+
 /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
    */
 #undef HAVE_SYS_DIR_H
 /* Define this if you want NFSv3 support compiled in */
 #undef NFS3_SUPPORTED
 
+/* Define this if you want NFSv41 support compiled in */
+#undef NFS41_SUPPORTED
+
 /* Define this if you want NFSv4 support compiled in */
 #undef NFS4_SUPPORTED
 
index a5cf482584af668e5f8a847909ec7e827a747705..470b2ec1cb74a0f4183ec326b9a95d48f5f10035 100644 (file)
@@ -99,10 +99,19 @@ int                         xtab_mount_write(void);
 int                            xtab_export_write(void);
 void                           xtab_append(nfs_export *);
 
+int                            secinfo_addflavor(struct flav_info *, struct exportent *);
+
 int                            rmtab_read(void);
 
 struct nfskey *                        key_lookup(char *hname);
 
+struct export_features {
+       unsigned int flags;
+       unsigned int secinfo_flags;
+};
+
+struct export_features *get_export_features(void);
+
 /* Record export error.  */
 extern int export_errno;
 
index efb70fb28378fe0e02b9eabb4f5515ed1c6eb245..11643361837af130dff1f14b5bf550908e6784a1 100644 (file)
@@ -53,11 +53,7 @@ ha_callout(char *event, char *arg1, char *arg2, int arg3)
                default: pid = waitpid(pid, &ret, 0);
        }
        sigaction(SIGCHLD, &oldact, &newact);
-#ifdef dprintf
-       dprintf(N_DEBUG, "ha callout returned %d\n", WEXITSTATUS(ret));
-#else
        xlog(D_GENERAL, "ha callout returned %d\n", WEXITSTATUS(ret));
-#endif
 }
 
 #endif
index a4160911086fcdb6816b4fe9cc87dd3d72ac1c79..0f0d09b4fd430c45a86c2c993a17627d109c2018 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -119,6 +120,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -185,6 +187,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index f7a99bab964b34ccf779f28b095c4986b303958e..1547a871360d9f187497e93cf1361434ca2e490f 100644 (file)
 #define NFSEXP_FSID            0x2000
 #define        NFSEXP_CROSSMOUNT       0x4000
 #define NFSEXP_NOACL           0x8000 /* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS                0xFFFF
+#define NFSEXP_V4ROOT          0x10000
+/*
+ * All flags supported by the kernel before addition of the
+ * export_features interface:
+ */
+#define NFSEXP_OLDFLAGS                0x7E3F
+/*
+ * Flags that can vary per flavor, for kernels before addition of the
+ * export_features interface:
+ */
+#define NFSEXP_OLD_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
+                                       | NFSEXP_ALLSQUASH)
 
 #endif /* _NSF_EXPORT_H */
index a64eb0a7fc0768191d425e2b6972d9071aa97000..c939d78105b6599857d659b9ba99178e85c98aa4 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _NFS_NFS_H
 #define _NFS_NFS_H
 
+#include <config.h>
+
 #include <linux/posix_types.h>
 #include <sys/types.h>
 #include <netinet/in.h>
 #define NFSD_MAXVERS 4
 
 #define NFSD_MINMINORVERS4 1
+#ifdef  NFS41_SUPPORTED
 #define NFSD_MAXMINORVERS4 1
+#else
+#define NFSD_MAXMINORVERS4 0
+#endif
 
 struct nfs_fh_len {
        int             fh_size;
index dff6af75159ca48e3729c5f81dccb8875b24d87f..4db35abf8d1a1df32c81db758c7cfc7b5f43968f 100644 (file)
@@ -58,16 +58,6 @@ static inline void nfs_clear_rpc_createerr(void)
        memset(&rpc_createerr, 0, sizeof(rpc_createerr));
 }
 
-/*
- * Extract port value from a socket address
- */
-extern uint16_t                nfs_get_port(const struct sockaddr *);
-
-/*
- * Set port value in a socket address
- */
-extern void            nfs_set_port(struct sockaddr *, const uint16_t);
-
 /*
  * Look up an RPC program name in /etc/rpc
  */
@@ -89,6 +79,18 @@ extern CLIENT                *nfs_get_priv_rpcclient( const struct sockaddr *,
                                const rpcprog_t, const rpcvers_t,
                                struct timeval *);
 
+/*
+ * Convert a netid to a protocol number and protocol family
+ */
+extern int             nfs_get_proto(const char *netid, sa_family_t *family,
+                               unsigned long *protocol);
+
+/*
+ * Convert a protocol family and protocol name to a netid
+ */
+extern char            *nfs_get_netid(const sa_family_t family,
+                               const unsigned long protocol);
+
 /*
  * Convert a socket address to a universal address
  */
@@ -158,4 +160,4 @@ extern int          nfs_rpc_ping(const struct sockaddr *sap,
                                const unsigned short protocol,
                                const struct timeval *timeout);
 
-#endif /* __NFS_UTILS_NFSRPC_H */
+#endif /* !__NFS_UTILS_NFSRPC_H */
diff --git a/support/include/nsm.h b/support/include/nsm.h
new file mode 100644 (file)
index 0000000..fb4d823
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ */
+
+#ifndef NFS_UTILS_SUPPORT_NSM_H
+#define NFS_UTILS_SUPPORT_NSM_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdbool.h>
+
+#include <netdb.h>
+#include <time.h>
+
+#include "sm_inter.h"
+
+typedef unsigned int
+               (*nsm_populate_t)(const char *hostname,
+                               const struct sockaddr *sap,
+                               const struct mon *mon,
+                               const time_t timestamp);
+
+/* file.c */
+
+extern _Bool   nsm_setup_pathnames(const char *progname,
+                               const char *parentdir);
+extern _Bool   nsm_is_default_parentdir(void);
+extern _Bool   nsm_drop_privileges(const int pidfd);
+
+extern int     nsm_get_state(_Bool update);
+extern void    nsm_update_kernel_state(const int state);
+
+extern unsigned int
+               nsm_retire_monitored_hosts(void);
+extern unsigned int
+               nsm_load_monitor_list(nsm_populate_t func);
+extern unsigned int
+               nsm_load_notify_list(nsm_populate_t func);
+
+extern _Bool   nsm_insert_monitored_host(const char *hostname,
+                       const struct sockaddr *sap, const struct mon *m);
+extern void    nsm_delete_monitored_host(const char *hostname,
+                       const char *mon_name, const char *my_name);
+extern void    nsm_delete_notified_host(const char *hostname,
+                       const char *mon_name, const char *my_name);
+extern size_t  nsm_priv_to_hex(const char *priv, char *buf,
+                               const size_t buflen);
+
+/* rpc.c */
+
+#define NSM_MAXMSGSIZE (2048u)
+
+extern uint32_t nsm_xmit_getport(const int sock,
+                       const struct sockaddr_in *sin,
+                       const unsigned long program,
+                       const unsigned long version);
+extern uint32_t nsm_xmit_getaddr(const int sock,
+                       const struct sockaddr_in6 *sin6,
+                       const rpcprog_t program, const rpcvers_t version);
+extern uint32_t nsm_xmit_rpcbind(const int sock, const struct sockaddr *sap,
+                       const rpcprog_t program, const rpcvers_t version);
+extern uint32_t nsm_xmit_notify(const int sock, const struct sockaddr *sap,
+                       const socklen_t salen, const rpcprog_t program,
+                       const char *mon_name, const int state);
+extern uint32_t nsm_xmit_nlmcall(const int sock, const struct sockaddr *sap,
+                       const socklen_t salen, const struct mon *m,
+                       const int state);
+extern uint32_t nsm_parse_reply(XDR *xdrs);
+extern unsigned long
+               nsm_recv_getport(XDR *xdrs);
+extern uint16_t nsm_recv_getaddr(XDR *xdrs);
+extern uint16_t nsm_recv_rpcbind(const sa_family_t family, XDR *xdrs);
+
+#endif /* !NFS_UTILS_SUPPORT_NSM_H */
index f551a8577acf3850d2e5a7d88b89659f94fd76d4..1b8f411ea8cc847c8bd2c23c1d576a5fbd487790 100644 (file)
@@ -41,7 +41,12 @@ struct rpc_dtable {
                (xdrproc_t)xdr_##res_type, sizeof(res_type), \
        }
 
-
+void           nfs_svc_unregister(const rpcprog_t program,
+                               const rpcvers_t version);
+unsigned int   nfs_svc_create(char *name, const rpcprog_t program,
+                               const rpcvers_t version,
+                               void (*dispatch)(struct svc_req *, SVCXPRT *),
+                               const uint16_t port);
 void           rpc_init(char *name, int prog, int vers,
                                void (*dispatch)(struct svc_req *, SVCXPRT *),
                                int defport);
index 935ed04b19395265497592fceb49807185ba0ce0..4a327405c6c2838bcb049e7561e6e29be4067cdc 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -119,6 +120,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -185,6 +187,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
diff --git a/support/include/sockaddr.h b/support/include/sockaddr.h
new file mode 100644 (file)
index 0000000..9af2543
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFS_UTILS_SOCKADDR_H
+#define NFS_UTILS_SOCKADDR_H
+
+#include <libio.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*
+ * This type is for defining buffers that contain network socket
+ * addresses.
+ *
+ * Casting a "struct sockaddr *" to the address of a "struct
+ * sockaddr_storage" breaks C aliasing rules.  The "union
+ * nfs_sockaddr" type follows C aliasing rules yet specifically
+ * allows converting pointers to it between "struct sockaddr *"
+ * and a few other network sockaddr-related pointer types.
+ *
+ * Note that this union is much smaller than a sockaddr_storage.
+ * It should be used only for AF_INET or AF_INET6 socket addresses.
+ * An AF_LOCAL sockaddr_un, for example, will clearly not fit into
+ * a buffer of this type.
+ */
+union nfs_sockaddr {
+       struct sockaddr         sa;
+       struct sockaddr_in      s4;
+       struct sockaddr_in6     s6;
+};
+
+#if SIZEOF_SOCKLEN_T - 0 == 0
+#define socklen_t unsigned int
+#endif
+
+#define SIZEOF_SOCKADDR_UNKNOWN        (socklen_t)0
+#define SIZEOF_SOCKADDR_IN     (socklen_t)sizeof(struct sockaddr_in)
+
+#ifdef IPV6_SUPPORTED
+#define SIZEOF_SOCKADDR_IN6    (socklen_t)sizeof(struct sockaddr_in6)
+#else  /* !IPV6_SUPPORTED */
+#define SIZEOF_SOCKADDR_IN6    SIZEOF_SOCKADDR_UNKNOWN
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_sockaddr_length - return the size in bytes of a socket address
+ * @sap: pointer to socket address
+ *
+ * Returns the size in bytes of @sap, or zero if the family is
+ * not recognized.
+ */
+static inline socklen_t
+nfs_sockaddr_length(const struct sockaddr *sap)
+{
+       switch (sap->sa_family) {
+       case AF_INET:
+               return SIZEOF_SOCKADDR_IN;
+       case AF_INET6:
+               return SIZEOF_SOCKADDR_IN6;
+       }
+       return SIZEOF_SOCKADDR_UNKNOWN;
+}
+
+static inline uint16_t
+get_port4(const struct sockaddr *sap)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+       return ntohs(sin->sin_port);
+}
+
+#ifdef IPV6_SUPPORTED
+static inline uint16_t
+get_port6(const struct sockaddr *sap)
+{
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
+       return ntohs(sin6->sin6_port);
+}
+#else  /* !IPV6_SUPPORTED */
+static inline uint16_t
+get_port6(__attribute__ ((unused)) const struct sockaddr *sap)
+{
+       return 0;
+}
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_get_port - extract port value from a socket address
+ * @sap: pointer to socket address
+ *
+ * Returns port value in host byte order, or zero if the
+ * socket address contains an unrecognized family.
+ */
+static inline uint16_t
+nfs_get_port(const struct sockaddr *sap)
+{
+       switch (sap->sa_family) {
+       case AF_INET:
+               return get_port4(sap);
+       case AF_INET6:
+               return get_port6(sap);
+       }
+       return 0;
+}
+
+static inline void
+set_port4(struct sockaddr *sap, const uint16_t port)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+       sin->sin_port = htons(port);
+}
+
+#ifdef IPV6_SUPPORTED
+static inline void
+set_port6(struct sockaddr *sap, const uint16_t port)
+{
+       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+       sin6->sin6_port = htons(port);
+}
+#else  /* !IPV6_SUPPORTED */
+static inline void
+set_port6(__attribute__ ((unused)) struct sockaddr *sap,
+               __attribute__ ((unused)) const uint16_t port)
+{
+}
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_set_port - set port value in a socket address
+ * @sap: pointer to socket address
+ * @port: port value to set
+ *
+ */
+static inline void
+nfs_set_port(struct sockaddr *sap, const uint16_t port)
+{
+       switch (sap->sa_family) {
+       case AF_INET:
+               set_port4(sap, port);
+               break;
+       case AF_INET6:
+               set_port6(sap, port);
+               break;
+       }
+}
+
+/**
+ * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback
+ * @sap: pointer to socket address
+ *
+ * Returns true if the socket address is the standard IPv4 loopback
+ * address; otherwise false is returned.
+ */
+static inline _Bool
+nfs_is_v4_loopback(const struct sockaddr *sap)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+
+       if (sin->sin_family != AF_INET)
+               return false;
+       if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+               return false;
+        return true;
+}
+
+static inline _Bool
+compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
+       return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
+}
+
+#ifdef IPV6_SUPPORTED
+static inline _Bool
+compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+       const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
+       const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
+
+       if ((IN6_IS_ADDR_LINKLOCAL((char *)&sin1->sin6_addr) &&
+            IN6_IS_ADDR_LINKLOCAL((char *)&sin2->sin6_addr)) ||
+           (IN6_IS_ADDR_SITELOCAL((char *)&sin1->sin6_addr) &&
+            IN6_IS_ADDR_SITELOCAL((char *)&sin2->sin6_addr)))
+               if (sin1->sin6_scope_id != sin2->sin6_scope_id)
+                       return false;
+
+       return IN6_ARE_ADDR_EQUAL((char *)&sin1->sin6_addr,
+                                       (char *)&sin2->sin6_addr);
+}
+#else  /* !IPV6_SUPPORTED */
+static inline _Bool
+compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1,
+               __attribute__ ((unused)) const struct sockaddr *sa2)
+{
+       return false;
+}
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_compare_sockaddr - compare two socket addresses for equality
+ * @sa1: pointer to a socket address
+ * @sa2: pointer to a socket address
+ *
+ * Returns true if the two socket addresses contain equivalent
+ * network addresses; otherwise false is returned.
+ */
+static inline _Bool
+nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+       if (sa1 == NULL || sa2 == NULL)
+               return false;
+
+       if (sa1->sa_family == sa2->sa_family)
+               switch (sa1->sa_family) {
+               case AF_INET:
+                       return compare_sockaddr4(sa1, sa2);
+               case AF_INET6:
+                       return compare_sockaddr6(sa1, sa2);
+               }
+
+       return false;
+}
+
+#endif /* !NFS_UTILS_SOCKADDR_H */
index f81de6ecda9d611764ea2b9d34e991d6a91d6620..bab471171882b824cd045f991f0d06844bcec547 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -40,6 +40,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -154,6 +155,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -220,6 +222,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -304,7 +307,7 @@ clean-libtool:
 #     (which will cause the Makefiles to be regenerated when you run `make');
 # (2) otherwise, pass the desired values on the `make' command line.
 $(RECURSIVE_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -329,7 +332,7 @@ $(RECURSIVE_TARGETS):
        fi; test -z "$$fail"
 
 $(RECURSIVE_CLEAN_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
index 5428b0344fd17a72a79bb3ad86d5164b19f35bfc..82dc4fb5c1c6e8789e7fa569074acb27da6b8144 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -119,6 +120,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -185,6 +187,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 98cf80686bc2a9d720d43bedd5946c517e2e7ad0..f73510696ff31d3f40d8086d3145e013e918074c 100644 (file)
@@ -5,14 +5,8 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-extern int verboselog;
-
-extern int allow_severity;
-extern int deny_severity;
-
-extern int good_client(char *daemon, struct sockaddr_in *addr);
-extern int from_local (struct sockaddr_in *addr);
-extern int check_default(char *daemon, struct sockaddr_in *addr,
-                        u_long proc, u_long prog);
+extern int from_local(const struct sockaddr *sap);
+extern int check_default(char *name, struct sockaddr *sap,
+                       const unsigned long program);
 
 #endif /* TCP_WRAPPER_H */
diff --git a/support/include/v4root.h b/support/include/v4root.h
new file mode 100644 (file)
index 0000000..706c15c
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ * support/include/v4root.h
+ *
+ * Support routines for dynamic pseudo roots.
+ *
+ */
+
+#ifndef V4ROOT_H
+#define V4ROOT_H
+
+extern int v4root_needed;
+extern void v4root_set(void);
+
+#endif /* V4ROOT_H */
index 9b62b27e7abda44c43a48e6c09125ef87eb03881..94a9877b16e9226e241272183d51f6492913bf4d 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -41,6 +41,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -137,6 +138,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -203,6 +205,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 89ccc4aca8644385980595966365120815518cff..e2de969266754f3f6ca39615c90cf511b69c28da 100644 (file)
 static char sccsid[] = "@(#) from_local.c 1.3 96/05/31 15:52:57";
 #endif
 
-#ifdef TEST
-#undef perror
+#ifdef HAVE_CONFIG_H
+#include <config.h>
 #endif
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <sys/ioctl.h>
-#include <syslog.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "sockaddr.h"
+#include "tcpwrapper.h"
+#include "xlog.h"
+
 #ifndef TRUE
 #define        TRUE    1
 #define FALSE  0
 #endif
 
- /*
-  * With virtual hosting, each hardware network interface can have multiple
-  * network addresses. On such machines the number of machine addresses can
-  * be surprisingly large.
-  */
+#ifdef HAVE_GETIFADDRS
+
+#include <ifaddrs.h>
+#include <time.h>
+
+/**
+ * from_local - determine whether request comes from the local system
+ * @sap: pointer to socket address to check
+ *
+ * With virtual hosting, each hardware network interface can have
+ * multiple network addresses. On such machines the number of machine
+ * addresses can be surprisingly large.
+ *
+ * We also expect the local network configuration to change over time,
+ * so call getifaddrs(3) more than once, but not too often.
+ *
+ * Returns TRUE if the sockaddr contains an address of one of the local
+ * network interfaces.  Otherwise FALSE is returned.
+ */
+int
+from_local(const struct sockaddr *sap)
+{
+       static struct ifaddrs *ifaddr = NULL;
+       static time_t last_update = 0;
+       struct ifaddrs *ifa;
+       unsigned int count;
+       time_t now;
+
+       if (time(&now) == ((time_t)-1)) {
+               xlog(L_ERROR, "%s: time(2): %m", __func__);
+
+               /* If we don't know what time it is, use the
+                * existing ifaddr list, if one exists  */
+               now = last_update;
+               if (ifaddr == NULL)
+                       now++;
+       }
+       if (now != last_update) {
+               xlog(D_GENERAL, "%s: updating local if addr list", __func__);
+
+               if (ifaddr)
+                       freeifaddrs(ifaddr);
+
+               if (getifaddrs(&ifaddr) == -1) {
+                       xlog(L_ERROR, "%s: getifaddrs(3): %m", __func__);
+                       return FALSE;
+               }
+
+               last_update = now;
+       }
+
+       count = 0;
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               if ((ifa->ifa_flags & IFF_UP) &&
+                   nfs_compare_sockaddr(sap, ifa->ifa_addr)) {
+                       xlog(D_GENERAL, "%s: incoming address matches "
+                                       "local interface address", __func__);
+                       return TRUE;
+               } else
+                       count++;
+       }
+
+       xlog(D_GENERAL, "%s: checked %u local if addrs; "
+                       "incoming address not found", __func__, count);
+       return FALSE;
+}
+
+#else  /* !HAVE_GETIFADDRS */
+
 static int num_local;
 static int num_addrs;
 static struct in_addr *addrs;
@@ -81,7 +149,7 @@ static int grow_addrs(void)
     new_num = (addrs == 0) ? 1 : num_addrs + num_addrs;
     new_addrs = (struct in_addr *) malloc(sizeof(*addrs) * new_num);
     if (new_addrs == 0) {
-       perror("portmap: out of memory");
+       xlog_warn("%s: out of memory", __func__);
        return (0);
     } else {
        if (addrs != 0) {
@@ -112,13 +180,13 @@ find_local(void)
      */
 
     if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
-       perror("socket");
+       xlog_warn("%s: socket(2): %m", __func__);
        return (0);
     }
     ifc.ifc_len = sizeof(buf);
     ifc.ifc_buf = buf;
     if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
-       perror("SIOCGIFCONF");
+       xlog_warn("%s: ioctl(SIOCGIFCONF): %m", __func__);
        (void) close(sock);
        return (0);
     }
@@ -130,10 +198,10 @@ find_local(void)
        if (ifr->ifr_addr.sa_family == AF_INET) {       /* IP net interface */
            ifreq = *ifr;
            if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
-               perror("SIOCGIFFLAGS");
+               xlog_warn("%s: ioctl(SIOCGIFFLAGS): %m", __func__);
            } else if (ifreq.ifr_flags & IFF_UP) {      /* active interface */
                if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
-                   perror("SIOCGIFADDR");
+                   xlog_warn("%s: ioctl(SIOCGIFADDR): %m", __func__);
                } else {
                    if (num_local >= num_addrs)
                        if (grow_addrs() == 0)
@@ -153,14 +221,28 @@ find_local(void)
     return (num_local);
 }
 
-/* from_local - determine whether request comes from the local system */
+/**
+ * from_local - determine whether request comes from the local system
+ * @sap: pointer to socket address to check
+ *
+ * With virtual hosting, each hardware network interface can have
+ * multiple network addresses. On such machines the number of machine
+ * addresses can be surprisingly large.
+ *
+ * Returns TRUE if the sockaddr contains an address of one of the local
+ * network interfaces.  Otherwise FALSE is returned.
+ */
 int
-from_local(struct sockaddr_in *addr)
+from_local(const struct sockaddr *sap)
 {
+    const struct sockaddr_in *addr = (const struct sockaddr_in *)sap;
     int     i;
 
+    if (sap->sa_family != AF_INET)
+       return (FALSE);
+
     if (addrs == 0 && find_local() == 0)
-       syslog(LOG_ERR, "cannot find any active local network interfaces");
+       xlog(L_ERROR, "Cannot find any active local network interfaces");
 
     for (i = 0; i < num_local; i++) {
        if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]),
@@ -172,9 +254,8 @@ from_local(struct sockaddr_in *addr)
 
 #ifdef TEST
 
-main()
+int main(void)
 {
-    char   *inet_ntoa();
     int     i;
 
     find_local();
@@ -182,4 +263,6 @@ main()
        printf("%s\n", inet_ntoa(addrs[i]));
 }
 
-#endif
+#endif /* TEST */
+
+#endif /* !HAVE_GETIFADDRS */
index 1da60204c541a3ee178d9a8ec869bc277387de93..06b0a463019ad08f7de34d3dad4bbaaf2ed8c93c 100644 (file)
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
+
 #ifdef HAVE_LIBWRAP
-#include <tcpwrapper.h>
 #include <unistd.h>
 #include <string.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
-#include <syslog.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <tcpd.h>
 
+#include "sockaddr.h"
+#include "tcpwrapper.h"
 #include "xlog.h"
 
 #ifdef SYSV40
 #include <netinet/in.h>
 #include <rpc/rpcent.h>
-#endif
+#endif /* SYSV40 */
 
-static void logit(int severity, struct sockaddr_in *addr,
-                 u_long procnum, u_long prognum, char *text);
-static int check_files(void);
+#define ALLOW 1
+#define DENY 0
 
-/*
- * These need to exist since they are externed 
- * public header files.
- */
-int     verboselog = 0;
-int     allow_severity = LOG_INFO;
-int     deny_severity = LOG_WARNING;
+#ifdef IPV6_SUPPORTED
+static void
+present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
+       socklen_t len = (socklen_t)buflen;
+
+       switch (sap->sa_family) {
+       case AF_INET:
+               if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0)
+                       return;
+       case AF_INET6:
+               if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, len) != 0)
+                       return;
+       }
 
-#define log_bad_host(addr, proc, prog) \
-  logit(deny_severity, addr, proc, prog, "request from unauthorized host")
+       memset(buf, 0, buflen);
+       strncpy(buf, "unrecognized caller", buflen);
+}
+#else  /* !IPV6_SUPPORTED */
+static void
+present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+       socklen_t len = (socklen_t)buflen;
 
-#define ALLOW 1
-#define DENY 0
+       if (sap->sa_family == AF_INET)
+               if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0)
+                       return;
+
+       memset(buf, 0, buflen);
+       strncpy(buf, "unrecognized caller", (size_t)buflen);
+}
+#endif /* !IPV6_SUPPORTED */
 
 typedef struct _haccess_t {
-       TAILQ_ENTRY(_haccess_t) list;
-       int access;
-    struct in_addr addr;
+       TAILQ_ENTRY(_haccess_t) list;
+       int                     allowed;
+       union nfs_sockaddr      address;
 } haccess_t;
 
 #define HASH_TABLE_SIZE 1021
 typedef struct _hash_head {
        TAILQ_HEAD(host_list, _haccess_t) h_head;
 } hash_head;
-hash_head haccess_tbl[HASH_TABLE_SIZE];
-static haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long);
-static void haccess_add(struct sockaddr_in *addr, u_long, int);
 
-inline unsigned int strtoint(char *str)
+static hash_head haccess_tbl[HASH_TABLE_SIZE];
+
+static unsigned long
+strtoint(const char *str)
 {
-       unsigned int n = 0;
-       int len = strlen(str);
-       int i;
+       unsigned long i, n = 0;
+       size_t len = strlen(str);
 
-       for (i=0; i < len; i++)
-               n+=((int)str[i])*i;
+       for (i = 0; i < len; i++)
+               n += (unsigned char)str[i] * i;
 
        return n;
 }
-static inline int hashint(unsigned int num)
+
+static unsigned int
+hashint(const unsigned long num)
 {
-       return num % HASH_TABLE_SIZE;
+       return (unsigned int)(num % HASH_TABLE_SIZE);
 }
-#define HASH(_addr, _prog) \
-       hashint((strtoint((_addr))+(_prog)))
 
-void haccess_add(struct sockaddr_in *addr, u_long prog, int access)
+static unsigned int
+HASH(const char *addr, const unsigned long program)
+{
+       return hashint(strtoint(addr) + program);
+}
+
+static void
+haccess_add(const struct sockaddr *sap, const char *address,
+               const unsigned long program, const int allowed)
 {
        hash_head *head;
-       haccess_t *hptr;
-       int hash;
+       haccess_t *hptr;
+       unsigned int hash;
 
        hptr = (haccess_t *)malloc(sizeof(haccess_t));
        if (hptr == NULL)
                return;
 
-       hash = HASH(inet_ntoa(addr->sin_addr), prog);
+       hash = HASH(address, program);
        head = &(haccess_tbl[hash]);
 
-       hptr->access = access;
-       hptr->addr.s_addr = addr->sin_addr.s_addr;
+       hptr->allowed = allowed;
+       memcpy(&hptr->address, sap, (size_t)nfs_sockaddr_length(sap));
 
        if (TAILQ_EMPTY(&head->h_head))
                TAILQ_INSERT_HEAD(&head->h_head, hptr, list);
        else
                TAILQ_INSERT_TAIL(&head->h_head, hptr, list);
 }
-haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long prog)
+
+static haccess_t *
+haccess_lookup(const struct sockaddr *sap, const char *address,
+               const unsigned long program)
 {
        hash_head *head;
-       haccess_t *hptr;
-       int hash;
+       haccess_t *hptr;
+       unsigned int hash;
 
-       hash = HASH(inet_ntoa(addr->sin_addr), prog);
+       hash = HASH(address, program);
        head = &(haccess_tbl[hash]);
 
        TAILQ_FOREACH(hptr, &head->h_head, list) {
-               if (hptr->addr.s_addr == addr->sin_addr.s_addr)
+               if (nfs_compare_sockaddr(&hptr->address.sa, sap))
                        return hptr;
        }
        return NULL;
 }
 
-int
-good_client(daemon, addr)
-char *daemon;
-struct sockaddr_in *addr;
+static void
+logit(const char *address)
+{
+       xlog_warn("connect from %s denied: request from unauthorized host",
+                       address);
+}
+
+static int
+good_client(char *name, struct sockaddr *sap)
 {
        struct request_info req;
 
-       request_init(&req, RQ_DAEMON, daemon, RQ_CLIENT_SIN, addr, 0);
+       request_init(&req, RQ_DAEMON, name, RQ_CLIENT_SIN, sap, 0);
        sock_methods(&req);
 
        if (hosts_access(&req)) 
@@ -159,9 +196,8 @@ struct sockaddr_in *addr;
        return DENY;
 }
 
-/* check_files - check to see if either access files have changed */
-
-static int check_files()
+static int
+check_files(void)
 {
        static time_t allow_mtime, deny_mtime;
        struct stat astat, dstat;
@@ -186,45 +222,48 @@ static int check_files()
        return changed;
 }
 
-/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
-
+/**
+ * check_default - additional checks for NULL, DUMP, GETPORT and unknown
+ * @name: pointer to '\0'-terminated ASCII string containing name of the
+ *             daemon requesting the access check
+ * @sap: pointer to sockaddr containing network address of caller
+ * @program: RPC program number caller is attempting to access
+ *
+ * Returns TRUE if the caller is allowed access; otherwise FALSE is returned.
+ */
 int
-check_default(daemon, addr, proc, prog)
-char *daemon;
-struct sockaddr_in *addr;
-u_long  proc;
-u_long  prog;
+check_default(char *name, struct sockaddr *sap, const unsigned long program)
 {
        haccess_t *acc = NULL;
        int changed = check_files();
+       char buf[INET6_ADDRSTRLEN];
+
+       present_address(sap, buf, sizeof(buf));
 
-       acc = haccess_lookup(addr, prog);
-       if (acc && changed == 0)
-               return (acc->access);
+       acc = haccess_lookup(sap, buf, program);
+       if (acc != NULL && changed == 0) {
+               xlog(D_GENERAL, "%s: access by %s %s (cached)", __func__,
+                       buf, acc->allowed ? "ALLOWED" : "DENIED");
+               return acc->allowed;
+       }
 
-       if (!(from_local(addr) || good_client(daemon, addr))) {
-               log_bad_host(addr, proc, prog);
-               if (acc)
-                       acc->access = FALSE;
-               else 
-                       haccess_add(addr, prog, FALSE);
+       if (!(from_local(sap) || good_client(name, sap))) {
+               logit(buf);
+               if (acc != NULL)
+                       acc->allowed = FALSE;
+               else
+                       haccess_add(sap, buf, program, FALSE);
+               xlog(D_GENERAL, "%s: access by %s DENIED", __func__, buf);
                return (FALSE);
        }
 
-       if (acc)
-               acc->access = TRUE;
-       else 
-               haccess_add(addr, prog, TRUE);
+       if (acc != NULL)
+               acc->allowed = TRUE;
+       else
+               haccess_add(sap, buf, program, TRUE);
+       xlog(D_GENERAL, "%s: access by %s ALLOWED", __func__, buf);
 
-    return (TRUE);
+       return (TRUE);
 }
 
-/* logit - report events of interest via the syslog daemon */
-
-static void logit(int severity, struct sockaddr_in *addr,
-                 u_long procnum, u_long prognum, char *text)
-{
-       syslog(severity, "connect from %s denied: %s",
-              inet_ntoa(addr->sin_addr), text);
-}
-#endif
+#endif /* HAVE_LIBWRAP */
index e9462fccca2260cea06d3a0e807f9e074d937b55..60400b2530e08342a866f195cad95617e0251c78 100644 (file)
@@ -4,7 +4,8 @@ noinst_LIBRARIES = libnfs.a
 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_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \
+                  svc_create.c
 
 MAINTAINERCLEANFILES = Makefile.in
 
index d6420cedef7f720bcd9ecb89b1d806c566173fd3..469abe70f378a4c151d80da99e2928cac99d458f 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -41,6 +41,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -65,7 +66,7 @@ am_libnfs_a_OBJECTS = exports.$(OBJEXT) rmtab.$(OBJEXT) xio.$(OBJEXT) \
        nfsexport.$(OBJEXT) getfh.$(OBJEXT) nfsctl.$(OBJEXT) \
        rpc_socket.$(OBJEXT) getport.$(OBJEXT) svc_socket.$(OBJEXT) \
        cacheio.$(OBJEXT) closeall.$(OBJEXT) nfs_mntent.$(OBJEXT) \
-       conffile.$(OBJEXT)
+       conffile.$(OBJEXT) svc_create.$(OBJEXT)
 libnfs_a_OBJECTS = $(am_libnfs_a_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include
 depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -142,6 +143,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -208,6 +210,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -247,7 +250,8 @@ noinst_LIBRARIES = libnfs.a
 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_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \
+                  svc_create.c
 
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
@@ -312,6 +316,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpc_socket.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpcdispatch.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpcmisc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svc_create.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svc_socket.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wildmat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcommon.Po@am__quote@
index 6a6ed5ac7f093a590e621895a03f2c9e3729683e..bdf5d849b1baa353d1939cc84b3a486d93354173 100644 (file)
@@ -285,9 +285,8 @@ int readline(int fd, char **buf, int *lenp)
 int
 check_new_cache(void)
 {
-       struct stat stb;
-       return  (stat("/proc/fs/nfs/filehandle", &stb) == 0) ||
-               (stat("/proc/fs/nfsd/filehandle", &stb) == 0);
+       return  (access("/proc/fs/nfs/filehandle", F_OK) == 0) ||
+               (access("/proc/fs/nfsd/filehandle", F_OK) == 0);
 }      
 
 
index 1aaebf4b777dfb10d1541726a1c2343f5b8037c7..a93941caf0ca6a87fea44d134d7591ee31106aac 100644 (file)
@@ -84,6 +84,31 @@ setexportent(char *fname, char *type)
        first = 1;
 }
 
+static void init_exportent (struct exportent *ee, int fromkernel)
+{
+       ee->e_flags = EXPORT_DEFAULT_FLAGS;
+       /* some kernels assume the default is sync rather than
+        * async.  More recent kernels always report one or other,
+        * but this test makes sure we assume same as kernel
+        * Ditto for wgather
+        */
+       if (fromkernel) {
+               ee->e_flags &= ~NFSEXP_ASYNC;
+               ee->e_flags &= ~NFSEXP_GATHERED_WRITES;
+       }
+       ee->e_anonuid = 65534;
+       ee->e_anongid = 65534;
+       ee->e_squids = NULL;
+       ee->e_sqgids = NULL;
+       ee->e_mountpoint = NULL;
+       ee->e_fslocmethod = FSLOC_NONE;
+       ee->e_fslocdata = NULL;
+       ee->e_secinfo[0].flav = NULL;
+       ee->e_nsquids = 0;
+       ee->e_nsqgids = 0;
+       ee->e_uuid = NULL;
+}
+
 struct exportent *
 getexportent(int fromkernel, int fromexports)
 {
@@ -102,26 +127,7 @@ getexportent(int fromkernel, int fromexports)
                has_default_opts = 0;
                has_default_subtree_opts = 0;
        
-               def_ee.e_flags = EXPORT_DEFAULT_FLAGS;
-               /* some kernels assume the default is sync rather than
-                * async.  More recent kernels always report one or other,
-                * but this test makes sure we assume same as kernel
-                * Ditto for wgather
-                */
-               if (fromkernel) {
-                       def_ee.e_flags &= ~NFSEXP_ASYNC;
-                       def_ee.e_flags &= ~NFSEXP_GATHERED_WRITES;
-               }
-               def_ee.e_anonuid = 65534;
-               def_ee.e_anongid = 65534;
-               def_ee.e_squids = NULL;
-               def_ee.e_sqgids = NULL;
-               def_ee.e_mountpoint = NULL;
-               def_ee.e_fslocmethod = FSLOC_NONE;
-               def_ee.e_fslocdata = NULL;
-               def_ee.e_secinfo[0].flav = NULL;
-               def_ee.e_nsquids = 0;
-               def_ee.e_nsqgids = 0;
+               init_exportent(&def_ee, fromkernel);
 
                ok = getpath(def_ee.e_path, sizeof(def_ee.e_path));
                if (ok <= 0)
@@ -334,18 +340,7 @@ mkexportent(char *hname, char *path, char *options)
 {
        static struct exportent ee;
 
-       ee.e_flags = EXPORT_DEFAULT_FLAGS;
-       ee.e_anonuid = 65534;
-       ee.e_anongid = 65534;
-       ee.e_squids = NULL;
-       ee.e_sqgids = NULL;
-       ee.e_mountpoint = NULL;
-       ee.e_fslocmethod = FSLOC_NONE;
-       ee.e_fslocdata = NULL;
-       ee.e_secinfo[0].flav = NULL;
-       ee.e_nsquids = 0;
-       ee.e_nsqgids = 0;
-       ee.e_uuid = NULL;
+       init_exportent(&ee, 0);
 
        xfree(ee.e_hostname);
        ee.e_hostname = xstrdup(hname);
@@ -385,7 +380,7 @@ static int valid_uuid(char *uuid)
  * do nothing if it's already there.  Returns the index of flavor
  * in the resulting array in any case.
  */
-static int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
+int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
 {
        struct sec_entry *p;
 
@@ -467,9 +462,20 @@ static void clearflags(int mask, unsigned int active, struct exportent *ep)
        }
 }
 
-/* options that can vary per flavor: */
-#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
-                                       | NFSEXP_ALLSQUASH)
+/*
+ * For those flags which are not allowed to vary by pseudoflavor,
+ * ensure that the export flags agree with the flags on each
+ * pseudoflavor:
+ */
+static void fix_pseudoflavor_flags(struct exportent *ep)
+{
+       struct export_features *ef;
+       struct sec_entry *p;
+
+       ef = get_export_features();
+       for (p = ep->e_secinfo; p->flav; p++)
+               p->flags |= ep->e_flags & ~ef->secinfo_flags;
+}
 
 /*
  * Parse option string pointed to by cp and set mount options accordingly.
@@ -477,7 +483,6 @@ static void clearflags(int mask, unsigned int active, struct exportent *ep)
 static int
 parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
 {
-       struct sec_entry *p;
        int     had_subtree_opt = 0;
        char    *flname = efname?efname:"command line";
        int     flline = efp?efp->x_line:0;
@@ -507,25 +512,25 @@ parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
                else if (strcmp(opt, "rw") == 0)
                        clearflags(NFSEXP_READONLY, active, ep);
                else if (!strcmp(opt, "secure"))
-                       ep->e_flags &= ~NFSEXP_INSECURE_PORT;
+                       clearflags(NFSEXP_INSECURE_PORT, active, ep);
                else if (!strcmp(opt, "insecure"))
-                       ep->e_flags |= NFSEXP_INSECURE_PORT;
+                       setflags(NFSEXP_INSECURE_PORT, active, ep);
                else if (!strcmp(opt, "sync"))
-                       ep->e_flags &= ~NFSEXP_ASYNC;
+                       clearflags(NFSEXP_ASYNC, active, ep);
                else if (!strcmp(opt, "async"))
-                       ep->e_flags |= NFSEXP_ASYNC;
+                       setflags(NFSEXP_ASYNC, active, ep);
                else if (!strcmp(opt, "nohide"))
-                       ep->e_flags |= NFSEXP_NOHIDE;
+                       setflags(NFSEXP_NOHIDE, active, ep);
                else if (!strcmp(opt, "hide"))
-                       ep->e_flags &= ~NFSEXP_NOHIDE;
+                       clearflags(NFSEXP_NOHIDE, active, ep);
                else if (!strcmp(opt, "crossmnt"))
-                       ep->e_flags |= NFSEXP_CROSSMOUNT;
+                       setflags(NFSEXP_CROSSMOUNT, active, ep);
                else if (!strcmp(opt, "nocrossmnt"))
-                       ep->e_flags &= ~NFSEXP_CROSSMOUNT;
+                       clearflags(NFSEXP_CROSSMOUNT, active, ep);
                else if (!strcmp(opt, "wdelay"))
-                       ep->e_flags |= NFSEXP_GATHERED_WRITES;
+                       setflags(NFSEXP_GATHERED_WRITES, active, ep);
                else if (!strcmp(opt, "no_wdelay"))
-                       ep->e_flags &= ~NFSEXP_GATHERED_WRITES;
+                       clearflags(NFSEXP_GATHERED_WRITES, active, ep);
                else if (strcmp(opt, "root_squash") == 0)
                        setflags(NFSEXP_ROOTSQUASH, active, ep);
                else if (!strcmp(opt, "no_root_squash"))
@@ -536,22 +541,22 @@ parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
                        clearflags(NFSEXP_ALLSQUASH, active, ep);
                else if (strcmp(opt, "subtree_check") == 0) {
                        had_subtree_opt = 1;
-                       ep->e_flags &= ~NFSEXP_NOSUBTREECHECK;
+                       clearflags(NFSEXP_NOSUBTREECHECK, active, ep);
                } else if (strcmp(opt, "no_subtree_check") == 0) {
                        had_subtree_opt = 1;
-                       ep->e_flags |= NFSEXP_NOSUBTREECHECK;
+                       setflags(NFSEXP_NOSUBTREECHECK, active, ep);
                } else if (strcmp(opt, "auth_nlm") == 0)
-                       ep->e_flags &= ~NFSEXP_NOAUTHNLM;
+                       clearflags(NFSEXP_NOAUTHNLM, active, ep);
                else if (strcmp(opt, "no_auth_nlm") == 0)
-                       ep->e_flags |= NFSEXP_NOAUTHNLM;
+                       setflags(NFSEXP_NOAUTHNLM, active, ep);
                else if (strcmp(opt, "secure_locks") == 0)
-                       ep->e_flags &= ~NFSEXP_NOAUTHNLM;
+                       clearflags(NFSEXP_NOAUTHNLM, active, ep);
                else if (strcmp(opt, "insecure_locks") == 0)
-                       ep->e_flags |= NFSEXP_NOAUTHNLM;
+                       setflags(NFSEXP_NOAUTHNLM, active, ep);
                else if (strcmp(opt, "acl") == 0)
-                       ep->e_flags &= ~NFSEXP_NOACL;
+                       clearflags(NFSEXP_NOACL, active, ep);
                else if (strcmp(opt, "no_acl") == 0)
-                       ep->e_flags |= NFSEXP_NOACL;
+                       setflags(NFSEXP_NOACL, active, ep);
                else if (strncmp(opt, "anonuid=", 8) == 0) {
                        char *oe;
                        ep->e_anonuid = strtol(opt+8, &oe, 10);
@@ -583,11 +588,11 @@ bad_option:
                        char *oe;
                        if (strcmp(opt+5, "root") == 0) {
                                ep->e_fsid = 0;
-                               ep->e_flags |= NFSEXP_FSID;
+                               setflags(NFSEXP_FSID, active, ep);
                        } else {
                                ep->e_fsid = strtoul(opt+5, &oe, 0);
                                if (opt[5]!='\0' && *oe == '\0') 
-                                       ep->e_flags |= NFSEXP_FSID;
+                                       setflags(NFSEXP_FSID, active, ep);
                                else if (valid_uuid(opt+5))
                                        ep->e_uuid = strdup(opt+5);
                                else {
@@ -628,22 +633,15 @@ bad_option:
                } else {
                        xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n",
                                        flname, flline, opt);
-                       ep->e_flags |= NFSEXP_ALLSQUASH | NFSEXP_READONLY;
+                       setflags(NFSEXP_ALLSQUASH | NFSEXP_READONLY, active, ep);
                        goto bad_option;
                }
                free(opt);
                while (isblank(*cp))
                        cp++;
        }
-       /*
-        * Turn on nohide which will allow this export to cross over
-        * the 'mount --bind' mount point.
-        */
-       if (ep->e_fslocdata)
-               ep->e_flags |= NFSEXP_NOHIDE;
 
-       for (p = ep->e_secinfo; p->flav; p++)
-               p->flags |= ep->e_flags & ~NFSEXP_SECINFO_FLAGS;
+       fix_pseudoflavor_flags(ep);
        ep->e_squids = squids;
        ep->e_sqgids = sqgids;
        ep->e_nsquids = nsquids;
@@ -760,4 +758,34 @@ syntaxerr(char *msg)
        xlog(L_ERROR, "%s:%d: syntax error: %s",
                        efname, efp?efp->x_line:0, msg);
 }
-
+struct export_features *get_export_features(void)
+{
+       static char *path = "/proc/fs/nfsd/export_features";
+       static struct export_features ef;
+       static int cached = 0;
+       char buf[50];
+       int c;
+       int fd;
+
+       if (cached)
+               return &ef;
+
+       ef.flags = NFSEXP_OLDFLAGS;
+       ef.secinfo_flags = NFSEXP_OLD_SECINFO_FLAGS;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               goto good;
+       fd = read(fd, buf, 50);
+       if (fd == -1)
+               goto err;
+       c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags);
+       if (c != 2)
+               goto err;
+good:
+       cached = 1;
+       return &ef;
+err:
+       xlog(L_WARNING, "unexpected error reading %s", path);
+       return &ef;
+}
index 4bdf556e092fc5e3e33dea26b87bf1a0b3dab128..c9305397680e46859362ff8114aa2075f2efdbf0 100644 (file)
@@ -45,6 +45,7 @@
 #include <rpc/rpcb_prot.h>
 #endif
 
+#include "sockaddr.h"
 #include "nfsrpc.h"
 
 /*
@@ -199,7 +200,63 @@ static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
        return clnt;
 }
 
-/*
+/**
+ * nfs_get_proto - Convert a netid to an address family and protocol number
+ * @netid: C string containing a netid
+ * @family: OUT: address family
+ * @protocol: OUT: protocol number
+ *
+ * Returns 1 and fills in @protocol if the netid was recognized;
+ * otherwise zero is returned.
+ */
+#ifdef HAVE_LIBTIRPC
+int
+nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol)
+{
+       struct netconfig *nconf;
+       struct protoent *proto;
+
+       nconf = getnetconfigent(netid);
+       if (nconf == NULL)
+               return 0;
+
+       proto = getprotobyname(nconf->nc_proto);
+       if (proto == NULL) {
+               freenetconfigent(nconf);
+               return 0;
+       }
+
+       *family = AF_UNSPEC;
+       if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
+               *family = AF_INET;
+       if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
+               *family = AF_INET6;
+       freenetconfigent(nconf);
+
+       *protocol = (unsigned long)proto->p_proto;
+       return 1;
+}
+#else  /* !HAVE_LIBTIRPC */
+int
+nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol)
+{
+       struct protoent *proto;
+
+       proto = getprotobyname(netid);
+       if (proto == NULL)
+               return 0;
+
+       *family = AF_INET;
+       *protocol = (unsigned long)proto->p_proto;
+       return 1;
+}
+#endif /* !HAVE_LIBTIRPC */
+
+/**
+ * nfs_get_netid - Convert a protocol family and protocol name to a netid
+ * @family: protocol family
+ * @protocol: protocol number
+ *
  * One of the arguments passed when querying remote rpcbind services
  * via rpcbind v3 or v4 is a netid string.  This replaces the pm_prot
  * field used in legacy PMAP_GETPORT calls.
@@ -213,13 +270,12 @@ static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
  * first entry that matches @family and @protocol and whose netid string
  * fits in the provided buffer.
  *
- * Returns a '\0'-terminated string if successful; otherwise NULL.
+ * Returns a '\0'-terminated string if successful.  Caller must
+ * free the returned string.  Otherwise NULL is returned, and
  * rpc_createerr.cf_stat is set to reflect the error.
  */
 #ifdef HAVE_LIBTIRPC
-
-static char *nfs_gp_get_netid(const sa_family_t family,
-                             const unsigned short protocol)
+char *nfs_get_netid(const sa_family_t family, const unsigned long protocol)
 {
        char *nc_protofmly, *nc_proto, *nc_netid;
        struct netconfig *nconf;
@@ -255,6 +311,9 @@ static char *nfs_gp_get_netid(const sa_family_t family,
 
                nc_netid = strdup(nconf->nc_netid);
                endnetconfig(handle);
+
+               if (nc_netid == NULL)
+                       rpc_createerr.cf_stat = RPC_SYSTEMERROR;
                return nc_netid;
        }
        endnetconfig(handle);
@@ -263,8 +322,28 @@ out:
        rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
        return NULL;
 }
+#else  /* !HAVE_LIBTIRPC */
+char *nfs_get_netid(const sa_family_t family, const unsigned long protocol)
+{
+       struct protoent *proto;
+       char *netid;
 
-#endif /* HAVE_LIBTIRPC */
+       if (family != AF_INET)
+               goto out;
+       proto = getprotobynumber((int)protocol);
+       if (proto == NULL)
+               goto out;
+
+       netid = strdup(proto->p_name);
+       if (netid == NULL)
+               rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+       return netid;
+
+out:
+       rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+       return NULL;
+}
+#endif /* !HAVE_LIBTIRPC */
 
 /*
  * Extract a port number from a universal address, and terminate the
@@ -421,7 +500,7 @@ static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
 {
        char *netid, *addr;
 
-       netid = nfs_gp_get_netid(sap->sa_family, protocol);
+       netid = nfs_get_netid(sap->sa_family, protocol);
        if (netid == NULL)
                return 0;
 
@@ -627,8 +706,8 @@ int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
                 const rpcprog_t program, const rpcvers_t version,
                 const unsigned short protocol, const struct timeval *timeout)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *saddr = (struct sockaddr *)&address;
+       union nfs_sockaddr address;
+       struct sockaddr *saddr = &address.sa;
        CLIENT *client;
        struct timeval tout = { -1, 0 };
        int result = 0;
@@ -696,8 +775,8 @@ unsigned short nfs_getport(const struct sockaddr *sap,
                           const rpcvers_t version,
                           const unsigned short protocol)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *saddr = (struct sockaddr *)&address;
+       union nfs_sockaddr address;
+       struct sockaddr *saddr = &address.sa;
        struct timeval timeout = { -1, 0 };
        unsigned short port = 0;
        CLIENT *client;
@@ -755,8 +834,8 @@ int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
        }
 
        if (port != 0) {
-               struct sockaddr_storage address;
-               struct sockaddr *saddr = (struct sockaddr *)&address;
+               union nfs_sockaddr address;
+               struct sockaddr *saddr = &address.sa;
 
                memcpy(saddr, sap, (size_t)salen);
                nfs_set_port(saddr, port);
@@ -807,8 +886,8 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
                                const rpcvers_t version,
                                const unsigned short protocol)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *lb_addr = (struct sockaddr *)&address;
+       union nfs_sockaddr address;
+       struct sockaddr *lb_addr = &address.sa;
        socklen_t lb_len = sizeof(*lb_addr);
        unsigned short port = 0;
 
@@ -891,8 +970,8 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
                                const unsigned short protocol,
                                const struct timeval *timeout)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *saddr = (struct sockaddr *)&address;
+       union nfs_sockaddr address;
+       struct sockaddr *saddr = &address.sa;
        CLIENT *client;
        struct rpcb parms;
        struct timeval tout = { -1, 0 };
index 4cbd28591270a184b68e7ecedddc4828080814bb..a28abf343898791b415336d36ef67c4977063d5f 100644 (file)
@@ -117,11 +117,24 @@ void
 fendrmtabent(FILE *fp)
 {
        if (fp) {
-               /* If it was written to, we really want
-                * to flush to disk before returning
-                */
-               fflush(fp);
-               fdatasync(fileno(fp));
+               static int have_new_cache = -1;
+               if (have_new_cache == -1) /* check only once */
+                       have_new_cache = check_new_cache();
+
+               if (!have_new_cache) {
+                       /*
+                        * If we are using the old caching interface: exportfs
+                        * uses the rmtab to determine what should be exported,
+                        * so it is important that it be up-to-date.
+                        *
+                        * If we are using the new caching interface: the rmtab
+                        * is ignored by exportfs and the fdatasync only serves
+                        * to slow us down.
+                        */
+                       fflush(fp);
+                       fdatasync(fileno(fp));
+               }
+
                fclose(fp);
        }
 }
index 9c20f61e5101d5fc8d3d50ff338bbfec7a0dca6c..0e20824cb614e4a23e69799a05a52adbdce6b58b 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <sys/types.h>
 #include <sys/time.h>
+
+#include <stdbool.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -38,6 +40,7 @@
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
 
+#include "sockaddr.h"
 #include "nfsrpc.h"
 
 #ifdef HAVE_LIBTIRPC
@@ -51,6 +54,7 @@
 #define NFSRPC_TIMEOUT_UDP     (3)
 #define NFSRPC_TIMEOUT_TCP     (10)
 
+
 /*
  * Set up an RPC client for communicating via a AF_LOCAL socket.
  *
@@ -121,10 +125,10 @@ static int nfs_bind(const int sock, const sa_family_t family)
 
        switch (family) {
        case AF_INET:
-               return bind(sock, (struct sockaddr *)&sin,
+               return bind(sock, (struct sockaddr *)(char *)&sin,
                                        (socklen_t)sizeof(sin));
        case AF_INET6:
-               return bind(sock, (struct sockaddr *)&sin6,
+               return bind(sock, (struct sockaddr *)(char *)&sin6,
                                        (socklen_t)sizeof(sin6));
        }
 
@@ -153,9 +157,9 @@ static int nfs_bindresvport(const int sock, const sa_family_t family)
 
        switch (family) {
        case AF_INET:
-               return bindresvport_sa(sock, (struct sockaddr *)&sin);
+               return bindresvport_sa(sock, (struct sockaddr *)(char *)&sin);
        case AF_INET6:
-               return bindresvport_sa(sock, (struct sockaddr *)&sin6);
+               return bindresvport_sa(sock, (struct sockaddr *)(char *)&sin6);
        }
 
        errno = EAFNOSUPPORT;
@@ -415,49 +419,6 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap,
        return client;
 }
 
-/**
- * nfs_get_port - extract port value from a socket address
- * @sap: pointer to socket address
- *
- * Returns port value in host byte order.
- */
-uint16_t
-nfs_get_port(const struct sockaddr *sap)
-{
-       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
-       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
-
-       switch (sap->sa_family) {
-       case AF_INET:
-               return ntohs(sin->sin_port);
-       case AF_INET6:
-               return ntohs(sin6->sin6_port);
-       }
-       return 0;
-}
-
-/**
- * nfs_set_port - set port value in a socket address
- * @sap: pointer to socket address
- * @port: port value to set
- *
- */
-void
-nfs_set_port(struct sockaddr *sap, const uint16_t port)
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *)sap;
-       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
-
-       switch (sap->sa_family) {
-       case AF_INET:
-               sin->sin_port = htons(port);
-               break;
-       case AF_INET6:
-               sin6->sin6_port = htons(port);
-               break;
-       }
-}
-
 /**
  * nfs_get_rpcclient - acquire an RPC client
  * @sap: pointer to socket address of RPC server
diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
new file mode 100644 (file)
index 0000000..59ba505
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <netinet/in.h>
+
+#include <sys/socket.h>
+#include <sys/resource.h>
+
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+
+#ifdef HAVE_TCP_WRAPPER
+#include "tcpwrapper.h"
+#endif
+
+#include "rpcmisc.h"
+#include "xlog.h"
+
+#ifdef HAVE_LIBTIRPC
+
+/*
+ * Set up an appropriate bind address, given @port and @nconf.
+ *
+ * Returns getaddrinfo(3) results if successful.  Caller must
+ * invoke freeaddrinfo(3) on these results.
+ *
+ * Otherwise NULL is returned if an error occurs.
+ */
+__attribute_malloc__
+static struct addrinfo *
+svc_create_bindaddr(struct netconfig *nconf, const uint16_t port)
+{
+       struct addrinfo *ai = NULL;
+       struct addrinfo hint = {
+               .ai_flags       = AI_PASSIVE | AI_NUMERICSERV,
+       };
+       char buf[8];
+       int error;
+
+       if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
+               hint.ai_family = AF_INET;
+#ifdef IPV6_SUPPORTED
+       else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
+               hint.ai_family = AF_INET6;
+#endif /* IPV6_SUPPORTED */
+       else {
+               xlog(D_GENERAL, "Unrecognized bind address family: %s",
+                       nconf->nc_protofmly);
+               return NULL;
+       }
+
+       if (strcmp(nconf->nc_proto, NC_UDP) == 0)
+               hint.ai_protocol = (int)IPPROTO_UDP;
+       else if (strcmp(nconf->nc_proto, NC_TCP) == 0)
+               hint.ai_protocol = (int)IPPROTO_TCP;
+       else {
+               xlog(D_GENERAL, "Unrecognized bind address protocol: %s",
+                       nconf->nc_proto);
+               return NULL;
+       }
+
+       (void)snprintf(buf, sizeof(buf), "%u", port);
+       error = getaddrinfo(NULL, buf, &hint, &ai);
+       if (error != 0) {
+               xlog(L_ERROR, "Failed to construct bind address: %s",
+                       gai_strerror(error));
+               return NULL;
+       }
+
+       return ai;
+}
+
+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)
+{
+       struct t_bind bindaddr;
+       struct addrinfo *ai;
+       SVCXPRT *xprt;
+
+       ai = svc_create_bindaddr(nconf, port);
+       if (ai == NULL)
+               return 0;
+
+       bindaddr.addr.buf = ai->ai_addr;
+       bindaddr.qlen = SOMAXCONN;
+
+       xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0);
+       freeaddrinfo(ai);
+       if (xprt == NULL) {
+               xlog(D_GENERAL, "Failed to create listener xprt "
+                               "(%s, %u, %s)", name, version, nconf->nc_netid);
+               return 0;
+       }
+
+       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);
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * nfs_svc_create - start up RPC svc listeners
+ * @name: C string containing name of new service
+ * @program: RPC program number to register
+ * @version: RPC version number to register
+ * @dispatch: address of function that handles incoming RPC requests
+ * @port: if not zero, transport listens on this port
+ *
+ * Sets up network transports for receiving RPC requests, and starts
+ * 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,
+               void (*dispatch)(struct svc_req *, SVCXPRT *),
+               const uint16_t port)
+{
+       const struct sigaction create_sigaction = {
+               .sa_handler     = SIG_IGN,
+       };
+       unsigned int visible, up;
+       struct netconfig *nconf;
+       void *handlep;
+
+       /*
+        * Ignore SIGPIPE to avoid exiting sideways when peers
+        * close their TCP connection while we're trying to reply
+        * to them.
+        */
+       (void)sigaction(SIGPIPE, &create_sigaction, NULL);
+
+       handlep = setnetconfig();
+       if (handlep == NULL) {
+               xlog(L_ERROR, "Failed to access local netconfig database: %s",
+                       nc_sperror());
+               return 0;
+       }
+
+       visible = 0;
+       up = 0;
+       while ((nconf = getnetconfig(handlep)) != NULL) {
+               if (!(nconf->nc_flag & NC_VISIBLE))
+                       continue;
+               visible++;
+               up += svc_create_nconf(name, program, version, dispatch,
+                                               port, nconf);
+       }
+
+       if (visible == 0)
+               xlog(L_ERROR, "Failed to find any visible netconfig entries");
+
+       if (endnetconfig(handlep) == -1)
+               xlog(L_ERROR, "Failed to close local netconfig database: %s",
+                       nc_sperror());
+
+       return up;
+}
+
+/**
+ * nfs_svc_unregister - remove service registrations from local rpcbind database
+ * @program: RPC program number to unregister
+ * @version: RPC version number to unregister
+ *
+ * Removes all registrations for [ @program, @version ] .
+ */
+void
+nfs_svc_unregister(const rpcprog_t program, const rpcvers_t version)
+{
+       if (rpcb_unset(program, version, NULL) == FALSE)
+               xlog(D_GENERAL, "Failed to unregister program %lu, version %lu",
+                       (unsigned long)program, (unsigned long)version);
+}
+
+#else  /* !HAVE_LIBTIRPC */
+
+/**
+ * nfs_svc_create - start up RPC svc listeners
+ * @name: C string containing name of new service
+ * @program: RPC program number to register
+ * @version: RPC version number to register
+ * @dispatch: address of function that handles incoming RPC requests
+ * @port: if not zero, transport listens on this port
+ *
+ * Sets up network transports for receiving RPC requests, and starts
+ * the RPC dispatcher.  Returns the number of started network transports.
+ */
+unsigned int
+nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
+               void (*dispatch)(struct svc_req *, SVCXPRT *),
+               const uint16_t port)
+{
+       rpc_init(name, (int)program, (int)version, dispatch, (int)port);
+       return 1;
+}
+
+/**
+ * nfs_svc_unregister - remove service registrations from local rpcbind database
+ * @program: RPC program number to unregister
+ * @version: RPC version number to unregister
+ *
+ * Removes all registrations for [ @program, @version ] .
+ */
+void
+nfs_svc_unregister(const rpcprog_t program, const rpcvers_t version)
+{
+       if (pmap_unset((unsigned long)program, (unsigned long)version) == FALSE)
+               xlog(D_GENERAL, "Failed to unregister program %lu, version %lu",
+                       (unsigned long)program, (unsigned long)version);
+}
+
+#endif /* !HAVE_LIBTIRPC */
index 5e2e1e95e7228d42ef81ed8b1f44bc7cc2db2d13..e3d27d2f943546720bc4b3070d33e551cba67a47 100644 (file)
@@ -44,16 +44,9 @@ xfclose(XFILE *xfp)
        xfree(xfp);
 }
 
-static void
-doalarm(int sig)
-{
-       return;
-}
-
 int
 xflock(char *fname, char *type)
 {
-       struct sigaction sa, oldsa;
        int             readonly = !strcmp(type, "r");
        struct flock    fl = { readonly? F_RDLCK : F_WRLCK, SEEK_SET, 0, 0, 0 };
        int             fd;
@@ -68,21 +61,12 @@ xflock(char *fname, char *type)
                return -1;
        }
 
-       sa.sa_handler = doalarm;
-       sa.sa_flags = 0;
-       sigemptyset(&sa.sa_mask);
-       sigaction(SIGALRM, &sa, &oldsa);
-       alarm(10);
        if (fcntl(fd, F_SETLKW, &fl) < 0) {
-               alarm(0);
                xlog(L_WARNING, "failed to lock %s: errno %d (%s)",
                                fname, errno, strerror(errno));
                close(fd);
-               fd = 0;
-       } else {
-               alarm(0);
+               fd = -1;
        }
-       sigaction(SIGALRM, &oldsa, NULL);
 
        return fd;
 }
diff --git a/support/nsm/Makefile.am b/support/nsm/Makefile.am
new file mode 100644 (file)
index 0000000..2038e68
--- /dev/null
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+GENFILES_CLNT  = sm_inter_clnt.c
+GENFILES_SVC   = sm_inter_svc.c
+GENFILES_XDR   = sm_inter_xdr.c
+GENFILES_H     = sm_inter.h
+
+GENFILES       = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
+
+EXTRA_DIST     = sm_inter.x
+
+noinst_LIBRARIES = libnsm.a
+libnsm_a_SOURCES = $(GENFILES) file.c rpc.c
+
+BUILT_SOURCES = $(GENFILES)
+
+if CONFIG_RPCGEN
+RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
+$(RPCGEN):
+       make -C ../../tools/rpcgen all
+else
+RPCGEN = @RPCGEN_PATH@
+endif
+
+$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -l -o $@ $<
+
+$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -m -o $@ $<
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -h -o $@ $<
+       rm -f $(top_builddir)/support/include/sm_inter.h
+       $(LN_S) ../nsm/sm_inter.h $(top_builddir)/support/include/sm_inter.h
+
+MAINTAINERCLEANFILES = Makefile.in
+
+CLEANFILES = $(GENFILES) $(top_builddir)/support/include/sm_inter.h
diff --git a/support/nsm/Makefile.in b/support/nsm/Makefile.in
new file mode 100644 (file)
index 0000000..7ce9d88
--- /dev/null
@@ -0,0 +1,569 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = support/nsm
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
+       $(top_srcdir)/aclocal/ipv6.m4 \
+       $(top_srcdir)/aclocal/kerberos5.m4 \
+       $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
+       $(top_srcdir)/aclocal/libevent.m4 \
+       $(top_srcdir)/aclocal/libnfsidmap.m4 \
+       $(top_srcdir)/aclocal/librpcsecgss.m4 \
+       $(top_srcdir)/aclocal/libtirpc.m4 \
+       $(top_srcdir)/aclocal/nfs-utils.m4 \
+       $(top_srcdir)/aclocal/rpcsec_vers.m4 \
+       $(top_srcdir)/aclocal/tcp-wrappers.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/support/include/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libnsm_a_AR = $(AR) $(ARFLAGS)
+libnsm_a_LIBADD =
+am__objects_1 = sm_inter_clnt.$(OBJEXT)
+am__objects_2 = sm_inter_svc.$(OBJEXT)
+am__objects_3 = sm_inter_xdr.$(OBJEXT)
+am__objects_4 =
+am__objects_5 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+       $(am__objects_4)
+am_libnsm_a_OBJECTS = $(am__objects_5) file.$(OBJEXT) rpc.$(OBJEXT)
+libnsm_a_OBJECTS = $(am_libnsm_a_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = $(libnsm_a_SOURCES)
+DIST_SOURCES = $(libnsm_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+GSSD = @GSSD@
+GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@
+GSSGLUE_LIBS = @GSSGLUE_LIBS@
+HAVE_LIBWRAP = @HAVE_LIBWRAP@
+HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@
+IDMAPD = @IDMAPD@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+K5VERS = @K5VERS@
+KRBCFLAGS = @KRBCFLAGS@
+KRBDIR = @KRBDIR@
+KRBLDFLAGS = @KRBLDFLAGS@
+KRBLIBS = @KRBLIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBLKID = @LIBBLKID@
+LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBTOOL = @LIBTOOL@
+LIBWRAP = @LIBWRAP@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+RELEASE = @RELEASE@
+RPCGEN_PATH = @RPCGEN_PATH@
+RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@
+RPCSECGSS_LIBS = @RPCSECGSS_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SVCGSSD = @SVCGSSD@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_gss = @enable_gss@
+enable_ipv6 = @enable_ipv6@
+enable_mountconfig = @enable_mountconfig@
+enable_nfsv3 = @enable_nfsv3@
+enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+kprefix = @kprefix@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mountfile = @mountfile@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+startstatd = @startstatd@
+statduser = @statduser@
+statedir = @statedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+GENFILES_CLNT = sm_inter_clnt.c
+GENFILES_SVC = sm_inter_svc.c
+GENFILES_XDR = sm_inter_xdr.c
+GENFILES_H = sm_inter.h
+GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
+EXTRA_DIST = sm_inter.x
+noinst_LIBRARIES = libnsm.a
+libnsm_a_SOURCES = $(GENFILES) file.c rpc.c
+BUILT_SOURCES = $(GENFILES)
+@CONFIG_RPCGEN_FALSE@RPCGEN = @RPCGEN_PATH@
+@CONFIG_RPCGEN_TRUE@RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = $(GENFILES) $(top_builddir)/support/include/sm_inter.h
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/nsm/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu support/nsm/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libnsm.a: $(libnsm_a_OBJECTS) $(libnsm_a_DEPENDENCIES) 
+       -rm -f libnsm.a
+       $(libnsm_a_AR) libnsm.a $(libnsm_a_OBJECTS) $(libnsm_a_LIBADD)
+       $(RANLIB) libnsm.a
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_clnt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_svc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_xdr.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libtool clean-noinstLIBRARIES ctags distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+@CONFIG_RPCGEN_TRUE@$(RPCGEN):
+@CONFIG_RPCGEN_TRUE@   make -C ../../tools/rpcgen all
+
+$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -l -o $@ $<
+
+$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -m -o $@ $<
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -h -o $@ $<
+       rm -f $(top_builddir)/support/include/sm_inter.h
+       $(LN_S) ../nsm/sm_inter.h $(top_builddir)/support/include/sm_inter.h
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/support/nsm/file.c b/support/nsm/file.c
new file mode 100644 (file)
index 0000000..d469219
--- /dev/null
@@ -0,0 +1,1067 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ *
+ * Callback information and NSM state is stored in files, usually
+ * under /var/lib/nfs.  A database of information contained in local
+ * files stores NLM callback data and what remote peers to notify of
+ * reboots.
+ *
+ * For each monitored remote peer, a text file is created under the
+ * directory specified by NSM_MONITOR_DIR.  The name of the file
+ * is a valid DNS hostname.  The hostname string must be a valid
+ * ASCII DNS name, and must not contain slash characters, white space,
+ * or '\0' (ie. anything that might have some special meaning in a
+ * path name).
+ *
+ * The contents of each file include seven blank-separated fields of
+ * text, finished with '\n'.  The first field contains the network
+ * address of the NLM service to call back.  The current implementation
+ * supports using only IPv4 addresses, so the only contents of this
+ * field are a network order IPv4 address expressed in 8 hexadecimal
+ * characters.
+ *
+ * The next four fields are text strings of hexadecimal characters,
+ * representing:
+ *
+ * 2. A 4 byte RPC program number of the NLM service to call back
+ * 3. A 4 byte RPC version number of the NLM service to call back
+ * 4. A 4 byte RPC procedure number of the NLM service to call back
+ * 5. A 16 byte opaque cookie that the NLM service uses to identify
+ *    the monitored host
+ *
+ * The sixth field is the monitored host's mon_name, passed to statd
+ * via an SM_MON request.
+ *
+ * The seventh field is the my_name for this peer, which is the
+ * hostname of the local NLM (currently on Linux, the result of
+ * `uname -n`).  This can be used as the source address/hostname
+ * when sending SM_NOTIFY requests.
+ *
+ * The NSM protocol does not limit the contents of these strings
+ * in any way except that they must fit into 1024 bytes.  Our
+ * implementation requires that these strings not contain
+ * white space or '\0'.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <string.h>
+#include <stdint.h>
+#ifndef S_SPLINT_S
+#include <unistd.h>
+#endif
+#include <libgen.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <grp.h>
+
+#include "xlog.h"
+#include "nsm.h"
+
+#define RPCARGSLEN     (4 * (8 + 1))
+#define LINELEN                (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1)
+
+#define NSM_KERNEL_STATE_FILE  "/proc/sys/fs/nfs/nsm_local_state"
+
+/*
+ * Some distributions place statd's files in a subdirectory
+ */
+#define NSM_PATH_EXTENSION
+/* #define NSM_PATH_EXTENSION  "/statd" */
+
+#define NSM_DEFAULT_STATEDIR           NFS_STATEDIR NSM_PATH_EXTENSION
+
+static char nsm_base_dirname[PATH_MAX] = NSM_DEFAULT_STATEDIR;
+
+#define NSM_MONITOR_DIR        "sm"
+#define NSM_NOTIFY_DIR "sm.bak"
+#define NSM_STATE_FILE "state"
+
+
+static _Bool
+error_check(const int len, const size_t buflen)
+{
+       return (len < 0) || ((size_t)len >= buflen);
+}
+
+static _Bool
+exact_error_check(const ssize_t len, const size_t buflen)
+{
+       return (len < 0) || ((size_t)len != buflen);
+}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs.  Caller must free the returned result with free(3).
+ */
+__attribute_malloc__
+static char *
+nsm_make_record_pathname(const char *directory, const char *hostname)
+{
+       const char *c;
+       size_t size;
+       char *path;
+       int len;
+
+       /*
+        * Block hostnames that contain characters that have
+        * meaning to the file system (like '/'), or that can
+        * be confusing on visual inspection (like ' ').
+        */
+       for (c = hostname; *c != '\0'; c++)
+               if (*c == '/' || isspace((int)*c) != 0) {
+                       xlog(D_GENERAL, "Hostname contains invalid characters");
+                       return NULL;
+               }
+
+       size = strlen(nsm_base_dirname) + strlen(directory) + strlen(hostname) + 3;
+       if (size > PATH_MAX) {
+               xlog(D_GENERAL, "Hostname results in pathname that is too long");
+               return NULL;
+       }
+
+       path = malloc(size);
+       if (path == NULL) {
+               xlog(D_GENERAL, "Failed to allocate memory for pathname");
+               return NULL;
+       }
+
+       len = snprintf(path, size, "%s/%s/%s",
+                       nsm_base_dirname, directory, hostname);
+       if (error_check(len, size)) {
+               xlog(D_GENERAL, "Pathname did not fit in specified buffer");
+               free(path);
+               return NULL;
+       }
+
+       return path;
+}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs.  Caller must free the returned result with free(3).
+ */
+__attribute_malloc__
+static char *
+nsm_make_pathname(const char *directory)
+{
+       size_t size;
+       char *path;
+       int len;
+
+       size = strlen(nsm_base_dirname) + strlen(directory) + 2;
+       if (size > PATH_MAX)
+               return NULL;
+
+       path = malloc(size);
+       if (path == NULL)
+               return NULL;
+
+       len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory);
+       if (error_check(len, size)) {
+               free(path);
+               return NULL;
+       }
+
+       return path;
+}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs.  Caller must free the returned result with free(3).
+ */
+__attribute_malloc__
+static char *
+nsm_make_temp_pathname(const char *pathname)
+{
+       size_t size;
+       char *path;
+       int len;
+
+       size = strlen(pathname) + sizeof(".new") + 2;
+       if (size > PATH_MAX)
+               return NULL;
+
+       path = malloc(size);
+       if (path == NULL)
+               return NULL;
+
+       len = snprintf(path, size, "%s.new", pathname);
+       if (error_check(len, size)) {
+               free(path);
+               return NULL;
+       }
+
+       return path;
+}
+
+/*
+ * Use "mktemp, write, rename" to update the contents of a file atomically.
+ *
+ * Returns true if completely successful, or false if some error occurred.
+ */
+static _Bool
+nsm_atomic_write(const char *path, const void *buf, const size_t buflen)
+{
+       _Bool result = false;
+       ssize_t len;
+       char *temp;
+       int fd;
+
+       temp = nsm_make_temp_pathname(path);
+       if (temp == NULL) {
+               xlog(L_ERROR, "Failed to create new path for %s", path);
+               goto out;
+       }
+
+       fd = open(temp, O_CREAT | O_TRUNC | O_SYNC | O_WRONLY, 0644);
+       if (fd == -1) {
+               xlog(L_ERROR, "Failed to create %s: %m", temp);
+               goto out;
+       }
+
+       len = write(fd, buf, buflen);
+       if (exact_error_check(len, buflen)) {
+               xlog(L_ERROR, "Failed to write %s: %m", temp);
+               (void)close(fd);
+               (void)unlink(temp);
+               goto out;
+       }
+
+       if (close(fd) == -1) {
+               xlog(L_ERROR, "Failed to close %s: %m", temp);
+               (void)unlink(temp);
+               goto out;
+       }
+
+       if (rename(temp, path) == -1) {
+               xlog(L_ERROR, "Failed to rename %s -> %s: %m",
+                               temp, path);
+               (void)unlink(temp);
+               goto out;
+       }
+
+       /* Ostensibly, a sync(2) is not needed here because
+        * open(O_CREAT), write(O_SYNC), and rename(2) are
+        * already synchronous with persistent storage, for
+        * any file system we care about. */
+
+       result = true;
+
+out:
+       free(temp);
+       return result;
+}
+
+/**
+ * nsm_setup_pathnames - set up pathname
+ * @progname: C string containing name of program, for error messages
+ * @parentdir: C string containing pathname to on-disk state, or NULL
+ *
+ * This runs before logging is set up, so error messages are directed
+ * to stderr.
+ *
+ * Returns true and sets up our pathnames, if @parentdir was valid
+ * and usable; otherwise false is returned.
+ */
+_Bool
+nsm_setup_pathnames(const char *progname, const char *parentdir)
+{
+       static char buf[PATH_MAX];
+       struct stat st;
+       char *path;
+
+       /* First: test length of name and whether it exists */
+       if (lstat(parentdir, &st) == -1) {
+               (void)fprintf(stderr, "%s: Failed to stat %s: %s",
+                               progname, parentdir, strerror(errno));
+               return false;
+       }
+
+       /* Ensure we have a clean directory pathname */
+       strncpy(buf, parentdir, sizeof(buf));
+       path = dirname(buf);
+       if (*path == '.') {
+               (void)fprintf(stderr, "%s: Unusable directory %s",
+                               progname, parentdir);
+               return false;
+       }
+
+       xlog(D_CALL, "Using %s as the state directory", parentdir);
+       strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname));
+       return true;
+}
+
+/**
+ * nsm_is_default_parentdir - check if parent directory is default
+ *
+ * Returns true if the active statd parent directory, set by
+ * nsm_change_pathname(), is the same as the built-in default
+ * parent directory; otherwise false is returned.
+ */
+_Bool
+nsm_is_default_parentdir(void)
+{
+       return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0;
+}
+
+/*
+ * Clear all capabilities but CAP_NET_BIND_SERVICE.  This permits
+ * callers to acquire privileged source ports, but all other root
+ * capabilities are disallowed.
+ *
+ * Returns true if successful, or false if some error occurred.
+ */
+static _Bool
+nsm_clear_capabilities(void)
+{
+       cap_t caps;
+
+       caps = cap_from_text("cap_net_bind_service=ep");
+       if (caps == NULL) {
+               xlog(L_ERROR, "Failed to allocate capability: %m");
+               return false;
+       }
+
+       if (cap_set_proc(caps) == -1) {
+               xlog(L_ERROR, "Failed to set capability flags: %m");
+               (void)cap_free(caps);
+               return false;
+       }
+
+       (void)cap_free(caps);
+       return true;
+}
+
+/**
+ * nsm_drop_privileges - drop root privileges
+ * @pidfd: file descriptor of a pid file
+ *
+ * Returns true if successful, or false if some error occurred.
+ *
+ * Set our effective UID and GID to that of our on-disk database.
+ */
+_Bool
+nsm_drop_privileges(const int pidfd)
+{
+       struct stat st;
+
+       (void)umask(S_IRWXO);
+
+       /*
+        * XXX: If we can't stat dirname, or if dirname is owned by
+        *      root, we should use "statduser" instead, which is set up
+        *      by configure.ac.  Nothing in nfs-utils seems to use
+        *      "statduser," though.
+        */
+       if (lstat(nsm_base_dirname, &st) == -1) {
+               xlog(L_ERROR, "Failed to stat %s: %m", nsm_base_dirname);
+               return false;
+       }
+
+       if (st.st_uid == 0) {
+               xlog_warn("Running as root.  "
+                       "chown %s to choose different user", nsm_base_dirname);
+               return true;
+       }
+
+       if (chdir(nsm_base_dirname) == -1) {
+               xlog(L_ERROR, "Failed to change working directory to %s: %m",
+                               nsm_base_dirname);
+               return false;
+       }
+
+       /*
+        * If the pidfile happens to reside on NFS, dropping privileges
+        * will probably cause us to lose access, even though we are
+        * holding it open.  Chown it to prevent this.
+        */
+       if (pidfd >= 0)
+               if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
+                       xlog_warn("Failed to change owner of pidfile: %m");
+
+       /*
+        * Don't clear capabilities when dropping root.
+        */
+        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+                xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
+               return 0;
+       }
+
+       if (setgroups(0, NULL) == -1) {
+               xlog(L_ERROR, "Failed to drop supplementary groups: %m");
+               return false;
+       }
+
+       /*
+        * ORDER
+        *
+        * setgid(2) first, as setuid(2) may remove privileges needed
+        * to set the group id.
+        */
+       if (setgid(st.st_gid) == -1 || setuid(st.st_uid) == -1) {
+               xlog(L_ERROR, "Failed to drop privileges: %m");
+               return false;
+       }
+
+       xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);
+
+       return nsm_clear_capabilities();
+}
+
+/**
+ * nsm_get_state - retrieve on-disk NSM state number
+ *
+ * Returns an odd NSM state number read from disk, or an initial
+ * state number.  Zero is returned if some error occurs.
+ */
+int
+nsm_get_state(_Bool update)
+{
+       int fd, state = 0;
+       ssize_t result;
+       char *path = NULL;
+
+       path = nsm_make_pathname(NSM_STATE_FILE);
+       if (path == NULL) {
+               xlog(L_ERROR, "Failed to allocate path for " NSM_STATE_FILE);
+               goto out;
+       }
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               if (errno != ENOENT) {
+                       xlog(L_ERROR, "Failed to open %s: %m", path);
+                       goto out;
+               }
+
+               xlog(L_NOTICE, "Initializing NSM state");
+               state = 1;
+               update = true;
+               goto update;
+       }
+
+       result = read(fd, &state, sizeof(state));
+       if (exact_error_check(result, sizeof(state))) {
+               xlog_warn("Failed to read %s: %m", path);
+
+               xlog(L_NOTICE, "Initializing NSM state");
+               state = 1;
+               update = true;
+               goto update;
+       }
+
+       if ((state & 1) == 0)
+               state++;
+
+update:
+       (void)close(fd);
+
+       if (update) {
+               state += 2;
+               if (!nsm_atomic_write(path, &state, sizeof(state)))
+                       state = 0;
+       }
+
+out:
+       free(path);
+       return state;
+}
+
+/**
+ * nsm_update_kernel_state - attempt to post new NSM state to kernel
+ * @state: NSM state number
+ *
+ */
+void
+nsm_update_kernel_state(const int state)
+{
+       ssize_t result;
+       char buf[20];
+       int fd, len;
+
+       fd = open(NSM_KERNEL_STATE_FILE, O_WRONLY);
+       if (fd == -1) {
+               xlog(D_GENERAL, "Failed to open " NSM_KERNEL_STATE_FILE ": %m");
+               return;
+       }
+
+       len = snprintf(buf, sizeof(buf), "%d", state);
+       if (error_check(len, sizeof(buf))) {
+               xlog_warn("Failed to form NSM state number string");
+               return;
+       }
+
+       result = write(fd, buf, strlen(buf));
+       if (exact_error_check(result, strlen(buf)))
+               xlog_warn("Failed to write NSM state number: %m");
+
+       if (close(fd) == -1)
+               xlog(L_ERROR, "Failed to close NSM state file "
+                               NSM_KERNEL_STATE_FILE ": %m");
+}
+
+/**
+ * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/"
+ *
+ * Returns the count of host records that were moved.
+ *
+ * Note that if any error occurs during this process, some monitor
+ * records may be left in the "sm" directory.
+ */
+unsigned int
+nsm_retire_monitored_hosts(void)
+{
+       unsigned int count = 0;
+       struct dirent *de;
+       char *path;
+       DIR *dir;
+
+       path = nsm_make_pathname(NSM_MONITOR_DIR);
+       if (path == NULL) {
+               xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR);
+               return count;
+       }
+
+       dir = opendir(path);
+       free(path);
+       if (dir == NULL) {
+               xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m");
+               return count;
+       }
+
+       while ((de = readdir(dir)) != NULL) {
+               char *src, *dst;
+
+               if (de->d_type != (unsigned char)DT_REG)
+                       continue;
+               if (de->d_name[0] == '.')
+                       continue;
+
+               src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name);
+               if (src == NULL) {
+                       xlog_warn("Bad monitor file name, skipping");
+                       continue;
+               }
+
+               dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name);
+               if (dst == NULL) {
+                       free(src);
+                       xlog_warn("Bad notify file name, skipping");
+                       continue;
+               }
+
+               if (rename(src, dst) == -1)
+                       xlog_warn("Failed to rename %s -> %s: %m",
+                               src, dst);
+               else {
+                       xlog(D_GENERAL, "Retired record for mon_name %s",
+                                       de->d_name);
+                       count++;
+               }
+
+               free(dst);
+               free(src);
+       }
+
+       (void)closedir(dir);
+       return count;
+}
+
+/*
+ * nsm_priv_to_hex - convert a NSM private cookie to a hex string.
+ *
+ * @priv: buffer holding the binary NSM private cookie
+ * @buf: output buffer for NULL terminated hex string
+ * @buflen: size of output buffer
+ *
+ * Returns the length of the resulting string or 0 on error
+ */
+size_t
+nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen)
+{
+       int i, len;
+       size_t remaining = buflen;
+
+       for (i = 0; i < SM_PRIV_SIZE; i++) {
+               len = snprintf(buf, remaining, "%02x",
+                               (unsigned int)(0xff & priv[i]));
+               if (error_check(len, remaining))
+                       return 0;
+               buf += len;
+               remaining -= (size_t)len;
+       }
+
+       return buflen - remaining;
+}
+
+/*
+ * Returns the length in bytes of the created record.
+ */
+__attribute_noinline__
+static size_t
+nsm_create_monitor_record(char *buf, const size_t buflen,
+               const struct sockaddr *sap, const struct mon *m)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+       size_t hexlen, remaining = buflen;
+       int len;
+
+       len = snprintf(buf, remaining, "%08x %08x %08x %08x ",
+                       (unsigned int)sin->sin_addr.s_addr,
+                       (unsigned int)m->mon_id.my_id.my_prog,
+                       (unsigned int)m->mon_id.my_id.my_vers,
+                       (unsigned int)m->mon_id.my_id.my_proc);
+       if (error_check(len, remaining))
+               return 0;
+       buf += len;
+       remaining -= (size_t)len;
+
+       hexlen = nsm_priv_to_hex(m->priv, buf, remaining);
+       if (hexlen == 0)
+               return 0;
+       buf += hexlen;
+       remaining -= hexlen;
+
+       len = snprintf(buf, remaining, " %s %s\n",
+                       m->mon_id.mon_name, m->mon_id.my_id.my_name);
+       if (error_check(len, remaining))
+               return 0;
+       remaining -= (size_t)len;
+
+       return buflen - remaining;
+}
+
+static _Bool
+nsm_append_monitored_host(const char *path, const char *line)
+{
+       _Bool result = false;
+       char *buf = NULL;
+       struct stat stb;
+       size_t buflen;
+       ssize_t len;
+       int fd;
+
+       if (stat(path, &stb) == -1) {
+               xlog(L_ERROR, "Failed to insert: "
+                       "could not stat original file %s: %m", path);
+               goto out;
+       }
+       buflen = (size_t)stb.st_size + strlen(line);
+
+       buf = malloc(buflen + 1);
+       if (buf == NULL) {
+               xlog(L_ERROR, "Failed to insert: no memory");
+               goto out;
+       }
+       memset(buf, 0, buflen + 1);
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               xlog(L_ERROR, "Failed to insert: "
+                       "could not open original file %s: %m", path);
+               goto out;
+       }
+
+       len = read(fd, buf, (size_t)stb.st_size);
+       if (exact_error_check(len, (size_t)stb.st_size)) {
+               xlog(L_ERROR, "Failed to insert: "
+                       "could not read original file %s: %m", path);
+               (void)close(fd);
+               goto out;
+       }
+       (void)close(fd);
+
+       strcat(buf, line);
+
+       if (nsm_atomic_write(path, buf, buflen))
+               result = true;
+
+out:
+       free(buf);
+       return result;
+}
+
+/**
+ * nsm_insert_monitored_host - write callback data for one host to disk
+ * @hostname: C string containing a hostname
+ * @sap: sockaddr containing NLM callback address
+ * @mon: SM_MON arguments to save
+ *
+ * Returns true if successful, otherwise false if some error occurs.
+ */
+_Bool
+nsm_insert_monitored_host(const char *hostname, const struct sockaddr *sap,
+               const struct mon *m)
+{
+       static char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
+       char *path;
+       _Bool result = false;
+       ssize_t len;
+       size_t size;
+       int fd;
+
+       path = nsm_make_record_pathname(NSM_MONITOR_DIR, hostname);
+       if (path == NULL) {
+               xlog(L_ERROR, "Failed to insert: bad monitor hostname '%s'",
+                               hostname);
+               return false;
+       }
+
+       size = nsm_create_monitor_record(buf, sizeof(buf), sap, m);
+       if (size == 0) {
+               xlog(L_ERROR, "Failed to insert: record too long");
+               goto out;
+       }
+
+       /*
+        * If exclusive create fails, we're adding a new line to an
+        * existing file.
+        */
+       fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_SYNC, S_IRUSR | S_IWUSR);
+       if (fd == -1) {
+               if (errno != EEXIST) {
+                       xlog(L_ERROR, "Failed to insert: creating %s: %m", path);
+                       goto out;
+               }
+
+               result = nsm_append_monitored_host(path, buf);
+               goto out;
+       }
+       result = true;
+
+       len = write(fd, buf, size);
+       if (exact_error_check(len, size)) {
+               xlog_warn("Failed to insert: writing %s: %m", path);
+               (void)unlink(path);
+               result = false;
+       }
+
+       if (close(fd) == -1) {
+               xlog(L_ERROR, "Failed to insert: closing %s: %m", path);
+               (void)unlink(path);
+               result = false;
+       }
+
+out:
+       free(path);
+       return result;
+}
+
+__attribute_noinline__
+static _Bool
+nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m)
+{
+       unsigned int i, tmp;
+       int count;
+       char *c;
+
+       c = strchr(line, '\n');
+       if (c != NULL)
+               *c = '\0';
+
+       count = sscanf(line, "%8x %8x %8x %8x ",
+                       (unsigned int *)&sin->sin_addr.s_addr,
+                       (unsigned int *)&m->mon_id.my_id.my_prog,
+                       (unsigned int *)&m->mon_id.my_id.my_vers,
+                       (unsigned int *)&m->mon_id.my_id.my_proc);
+       if (count != 4)
+               return false;
+
+       c = line + RPCARGSLEN;
+       for (i = 0; i < SM_PRIV_SIZE; i++) {
+               if (sscanf(c, "%2x", &tmp) != 1)
+                       return false;
+               m->priv[i] = (char)tmp;
+               c += 2;
+       }
+
+       c++;
+       m->mon_id.mon_name = c;
+       while (*c != '\0' && *c != ' ')
+               c++;
+       if (*c != '\0')
+               *c++ = '\0';
+       while (*c == ' ')
+               c++;
+       m->mon_id.my_id.my_name = c;
+
+       return true;
+}
+
+/*
+ * Stuff a 'struct mon' with callback data, and call @func.
+ *
+ * Returns the count of in-core records created.
+ */
+static unsigned int
+nsm_read_line(const char *hostname, const time_t timestamp, char *line,
+               nsm_populate_t func)
+{
+       struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+       };
+       struct mon m;
+
+       if (!nsm_parse_line(line, &sin, &m))
+               return 0;
+
+       return func(hostname, (struct sockaddr *)(char *)&sin, &m, timestamp);
+}
+
+/*
+ * Given a filename, reads data from a file under NSM_MONITOR_DIR
+ * and invokes @func so caller can populate their in-core
+ * database with this data.
+ */
+static unsigned int
+nsm_load_host(const char *directory, const char *filename, nsm_populate_t func)
+{
+       char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
+       unsigned int result = 0;
+       struct stat stb;
+       char *path;
+       FILE *f;
+
+       path = nsm_make_record_pathname(directory, filename);
+       if (path == NULL)
+               goto out_err;
+
+       if (stat(path, &stb) == -1) {
+               xlog(L_ERROR, "Failed to stat %s: %m", path);
+               goto out_freepath;
+       }
+
+       f = fopen(path, "r");
+       if (f == NULL) {
+               xlog(L_ERROR, "Failed to open %s: %m", path);
+               goto out_freepath;
+       }
+
+       while (fgets(buf, (int)sizeof(buf), f) != NULL) {
+               buf[sizeof(buf) - 1] = '\0';
+               result += nsm_read_line(filename, stb.st_mtime, buf, func);
+       }
+       if (result == 0)
+               xlog(L_ERROR, "Failed to read monitor data from %s", path);
+
+       (void)fclose(f);
+
+out_freepath:
+       free(path);
+out_err:
+       return result;
+}
+
+static unsigned int
+nsm_load_dir(const char *directory, nsm_populate_t func)
+{
+       unsigned int count = 0;
+       struct dirent *de;
+       char *path;
+       DIR *dir;
+
+       path = nsm_make_pathname(directory);
+       if (path == NULL) {
+               xlog(L_ERROR, "Failed to allocate path for directory %s",
+                               directory);
+               return 0;
+       }
+
+       dir = opendir(path);
+       free(path);
+       if (dir == NULL) {
+               xlog(L_ERROR, "Failed to open directory %s: %m",
+                               directory);
+               return 0;
+       }
+
+       while ((de = readdir(dir)) != NULL) {
+               if (de->d_type != (unsigned char)DT_REG)
+                       continue;
+               if (de->d_name[0] == '.')
+                       continue;
+
+               count += nsm_load_host(directory, de->d_name, func);
+       }
+
+       (void)closedir(dir);
+       return count;
+}
+
+/**
+ * nsm_load_monitor_list - load list of hosts to monitor
+ * @func: callback function to create entry for one host
+ *
+ * Returns the count of hosts that were found in the directory.
+ */
+unsigned int
+nsm_load_monitor_list(nsm_populate_t func)
+{
+       return nsm_load_dir(NSM_MONITOR_DIR, func);
+}
+
+/**
+ * nsm_load_notify_list - load list of hosts to notify
+ * @func: callback function to create entry for one host
+ *
+ * Returns the count of hosts that were found in the directory.
+ */
+unsigned int
+nsm_load_notify_list(nsm_populate_t func)
+{
+       return nsm_load_dir(NSM_NOTIFY_DIR, func);
+}
+
+static void
+nsm_delete_host(const char *directory, const char *hostname,
+               const char *mon_name, const char *my_name)
+{
+       char line[LINELEN + 1 + SM_MAXSTRLEN + 2];
+       char *outbuf = NULL;
+       struct stat stb;
+       char *path, *next;
+       size_t remaining;
+       FILE *f;
+
+       path = nsm_make_record_pathname(directory, hostname);
+       if (path == NULL) {
+               xlog(L_ERROR, "Bad filename, not deleting");
+               return;
+       }
+
+       if (stat(path, &stb) == -1) {
+               xlog(L_ERROR, "Failed to delete: "
+                       "could not stat original file %s: %m", path);
+               goto out;
+       }
+       remaining = (size_t)stb.st_size + 1;
+
+       outbuf = malloc(remaining);
+       if (outbuf == NULL) {
+               xlog(L_ERROR, "Failed to delete: no memory");
+               goto out;
+       }
+
+       f = fopen(path, "r");
+       if (f == NULL) {
+               xlog(L_ERROR, "Failed to delete: "
+                       "could not open original file %s: %m", path);
+               goto out;
+       }
+
+       /*
+        * Walk the records in the file, and copy the non-matching
+        * ones to our output buffer.
+        */
+       next = outbuf;
+       while (fgets(line, (int)sizeof(line), f) != NULL) {
+               struct sockaddr_in sin;
+               struct mon m;
+               size_t len;
+
+               if (!nsm_parse_line(line, &sin, &m)) {
+                       xlog(L_ERROR, "Failed to delete: "
+                               "could not parse original file %s", path);
+                       (void)fclose(f);
+                       goto out;
+               }
+
+               if (strcmp(mon_name, m.mon_id.mon_name) == 0 &&
+                        strcmp(my_name, m.mon_id.my_id.my_name) == 0)
+                       continue;
+
+               /* nsm_parse_line destroys the contents of line[], so
+                * reconstruct the copy in our output buffer. */
+               len = nsm_create_monitor_record(next, remaining,
+                                       (struct sockaddr *)(char *)&sin, &m);
+               if (len == 0) {
+                       xlog(L_ERROR, "Failed to delete: "
+                               "could not construct output record");
+                       (void)fclose(f);
+                       goto out;
+               }
+               next += len;
+               remaining -= len;
+       }
+
+       (void)fclose(f);
+
+       /*
+        * If nothing was copied when we're done, then unlink the file.
+        * Otherwise, atomically update the contents of the file.
+        */
+       if (next != outbuf) {
+               if (!nsm_atomic_write(path, outbuf, strlen(outbuf)))
+                       xlog(L_ERROR, "Failed to delete: "
+                               "could not write new file %s: %m", path);
+       } else {
+               if (unlink(path) == -1)
+                       xlog(L_ERROR, "Failed to delete: "
+                               "could not unlink file %s: %m", path);
+       }
+
+out:
+       free(outbuf);
+       free(path);
+}
+
+/**
+ * nsm_delete_monitored_host - delete on-disk record for monitored host
+ * @hostname: '\0'-terminated C string containing hostname of record to delete
+ * @mon_name: '\0'-terminated C string containing monname of record to delete
+ * @my_name: '\0'-terminated C string containing myname of record to delete
+ *
+ */
+void
+nsm_delete_monitored_host(const char *hostname, const char *mon_name,
+               const char *my_name)
+{
+       nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name);
+}
+
+/**
+ * nsm_delete_notified_host - delete on-disk host record after notification
+ * @hostname: '\0'-terminated C string containing hostname of record to delete
+ * @mon_name: '\0'-terminated C string containing monname of record to delete
+ * @my_name: '\0'-terminated C string containing myname of record to delete
+ *
+ */
+void
+nsm_delete_notified_host(const char *hostname, const char *mon_name,
+               const char *my_name)
+{
+       nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name);
+}
diff --git a/support/nsm/rpc.c b/support/nsm/rpc.c
new file mode 100644 (file)
index 0000000..4e5f40e
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ *
+ * Instead of using ONC or TI RPC library calls, statd constructs
+ * RPC calls directly in socket buffers.  This allows a single
+ * socket to be concurrently shared among several different RPC
+ * programs and versions using a simple RPC request dispatcher.
+ *
+ * This file contains the details of RPC header and call
+ * construction and reply parsing, and a method for creating a
+ * socket for use with these functions.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <time.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_rmt.h>
+
+#ifdef HAVE_LIBTIRPC
+#include <netconfig.h>
+#include <rpc/rpcb_prot.h>
+#endif /* HAVE_LIBTIRPC */
+
+#include "xlog.h"
+#include "nfsrpc.h"
+#include "nsm.h"
+#include "sm_inter.h"
+
+/*
+ * Returns a fresh XID appropriate for RPC over UDP -- never zero.
+ */
+static uint32_t
+nsm_next_xid(void)
+{
+       static uint32_t nsm_xid = 0;
+       struct timeval now;
+
+       if (nsm_xid == 0) {
+               (void)gettimeofday(&now, NULL);
+               nsm_xid = (uint32_t)getpid() ^
+                               (uint32_t)now.tv_sec ^ (uint32_t)now.tv_usec;
+       }
+
+       return nsm_xid++;
+}
+
+/*
+ * Select a fresh XID and construct an RPC header in @mesg.
+ * Always use AUTH_NULL credentials and verifiers.
+ *
+ * Returns the new XID.
+ */
+static uint32_t
+nsm_init_rpc_header(const rpcprog_t program, const rpcvers_t version,
+                       const rpcproc_t procedure, struct rpc_msg *mesg)
+{
+       struct call_body *cb = &mesg->rm_call;
+       uint32_t xid = nsm_next_xid();
+
+       memset(mesg, 0, sizeof(*mesg));
+
+       mesg->rm_xid = (unsigned long)xid;
+       mesg->rm_direction = CALL;
+
+       cb->cb_rpcvers = RPC_MSG_VERSION;
+       cb->cb_prog = program;
+       cb->cb_vers = version;
+       cb->cb_proc = procedure;
+
+       cb->cb_cred.oa_flavor = AUTH_NULL;
+       cb->cb_cred.oa_base = (caddr_t) NULL;
+       cb->cb_cred.oa_length = 0;
+       cb->cb_verf.oa_flavor = AUTH_NULL;
+       cb->cb_verf.oa_base = (caddr_t) NULL;
+       cb->cb_verf.oa_length = 0;
+
+       return xid;
+}
+
+/*
+ * Initialize the network send buffer and XDR memory for encoding.
+ */
+static void
+nsm_init_xdrmem(char *msgbuf, const unsigned int msgbuflen,
+               XDR *xdrp)
+{
+       memset(msgbuf, 0, (size_t)msgbuflen);
+       memset(xdrp, 0, sizeof(*xdrp));
+       xdrmem_create(xdrp, msgbuf, msgbuflen, XDR_ENCODE);
+}
+
+/*
+ * Send a completed RPC call on a socket.
+ *
+ * Returns true if all the bytes were sent successfully; otherwise
+ * false if any error occurred.
+ */
+static _Bool
+nsm_rpc_sendto(const int sock, const struct sockaddr *sap,
+                       const socklen_t salen, XDR *xdrs, void *buf)
+{
+       const size_t buflen = (size_t)xdr_getpos(xdrs);
+       ssize_t err;
+
+       err = sendto(sock, buf, buflen, 0, sap, salen);
+       if ((err < 0) || ((size_t)err != buflen)) {
+               xlog(L_ERROR, "%s: sendto failed: %m", __func__);
+               return false;
+       }
+       return true;
+}
+
+/**
+ * nsm_xmit_getport - post a PMAP_GETPORT call on a socket descriptor
+ * @sock: datagram socket descriptor
+ * @sin: pointer to AF_INET socket address of server
+ * @program: RPC program number to query
+ * @version: RPC version number to query
+ *
+ * Send a PMAP_GETPORT call to the portmap daemon at @sin using
+ * socket descriptor @sock.  This request queries the RPC program
+ * [program, version, IPPROTO_UDP].
+ *
+ * NB: PMAP_GETPORT works only for IPv4 hosts.  This implementation
+ *     works only over UDP, and queries only UDP registrations.
+ *
+ * Returns the XID of the call, or zero if an error occurred.
+ */
+uint32_t
+nsm_xmit_getport(const int sock, const struct sockaddr_in *sin,
+                       const unsigned long program,
+                       const unsigned long version)
+{
+       char msgbuf[NSM_MAXMSGSIZE];
+       struct sockaddr_in addr;
+       struct rpc_msg mesg;
+       _Bool sent = false;
+       struct pmap parms = {
+               .pm_prog        = program,
+               .pm_vers        = version,
+               .pm_prot        = (unsigned long)IPPROTO_UDP,
+       };
+       uint32_t xid;
+       XDR xdr;
+
+       xlog(D_CALL, "Sending PMAP_GETPORT for %u, %u, udp", program, version);
+
+       nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
+       xid = nsm_init_rpc_header(PMAPPROG, PMAPVERS,
+                                       (rpcproc_t)PMAPPROC_GETPORT, &mesg);
+
+       addr = *sin;
+       addr.sin_port = htons(PMAPPORT);
+
+       if (xdr_callmsg(&xdr, &mesg) == TRUE &&
+           xdr_pmap(&xdr, &parms) == TRUE)
+               sent = nsm_rpc_sendto(sock, (struct sockaddr *)(char *)&addr,
+                                       (socklen_t)sizeof(addr), &xdr, msgbuf);
+       else
+               xlog(L_ERROR, "%s: can't encode PMAP_GETPORT call", __func__);
+
+       xdr_destroy(&xdr);
+
+       if (sent == false)
+               return 0;
+       return xid;
+}
+
+/**
+ * nsm_xmit_getaddr - post an RPCB_GETADDR call on a socket descriptor
+ * @sock: datagram socket descriptor
+ * @sin: pointer to AF_INET6 socket address of server
+ * @program: RPC program number to query
+ * @version: RPC version number to query
+ *
+ * Send an RPCB_GETADDR call to the rpcbind daemon at @sap using
+ * socket descriptor @sock.  This request queries the RPC program
+ * [program, version, "udp6"].
+ *
+ * NB: RPCB_GETADDR works for both IPv4 and IPv6 hosts.  This
+ *     implementation works only over UDP and AF_INET6, and queries
+ *     only "udp6" registrations.
+ *
+ * Returns the XID of the call, or zero if an error occurred.
+ */
+#ifdef HAVE_LIBTIRPC
+uint32_t
+nsm_xmit_getaddr(const int sock, const struct sockaddr_in6 *sin6,
+                       const rpcprog_t program, const rpcvers_t version)
+{
+       char msgbuf[NSM_MAXMSGSIZE];
+       struct sockaddr_in6 addr;
+       struct rpc_msg mesg;
+       _Bool sent = false;
+       struct rpcb parms = {
+               .r_prog         = program,
+               .r_vers         = version,
+               .r_netid        = "udp6",
+               .r_owner        = "",
+       };
+       uint32_t xid;
+       XDR xdr;
+
+       xlog(D_CALL, "Sending RPCB_GETADDR for %u, %u, udp6", program, version);
+
+       nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
+       xid = nsm_init_rpc_header(RPCBPROG, RPCBVERS,
+                                       (rpcproc_t)RPCBPROC_GETADDR, &mesg);
+
+       addr = *sin6;
+       addr.sin6_port = htons(PMAPPORT);
+       parms.r_addr = nfs_sockaddr2universal((struct sockaddr *)(char *)&addr);
+       if (parms.r_addr == NULL) {
+               xlog(L_ERROR, "%s: can't encode socket address", __func__);
+               return 0;
+       }
+
+       if (xdr_callmsg(&xdr, &mesg) == TRUE &&
+           xdr_rpcb(&xdr, &parms) == TRUE)
+               sent = nsm_rpc_sendto(sock, (struct sockaddr *)(char *)&addr,
+                                       (socklen_t)sizeof(addr), &xdr, msgbuf);
+       else
+               xlog(L_ERROR, "%s: can't encode RPCB_GETADDR call", __func__);
+
+       xdr_destroy(&xdr);
+       free(parms.r_addr);
+
+       if (sent == false)
+               return 0;
+       return xid;
+}
+#else  /* !HAVE_LIBTIRPC */
+uint32_t
+nsm_xmit_getaddr(const int sock __attribute__((unused)),
+                       const struct sockaddr_in6 *sin6 __attribute__((unused)),
+                       const rpcprog_t program __attribute__((unused)),
+                       const rpcvers_t version __attribute__((unused)))
+{
+       return 0;
+}
+#endif /* !HAVE_LIBTIRPC */
+
+/**
+ * nsm_xmit_rpcbind - post an rpcbind request
+ * @sock: datagram socket descriptor
+ * @sap: pointer to socket address of server
+ * @program: RPC program number to query
+ * @version: RPC version number to query
+ *
+ * Send an rpcbind query to the rpcbind daemon at @sap using
+ * socket descriptor @sock.
+ *
+ * NB: This implementation works only over UDP, but can query IPv4 or IPv6
+ *     hosts.  It queries only UDP registrations.
+ *
+ * Returns the XID of the call, or zero if an error occurred.
+ */
+uint32_t
+nsm_xmit_rpcbind(const int sock, const struct sockaddr *sap,
+                       const rpcprog_t program, const rpcvers_t version)
+{
+       switch (sap->sa_family) {
+       case AF_INET:
+               return nsm_xmit_getport(sock, (const struct sockaddr_in *)sap,
+                                               program, version);
+       case AF_INET6:
+               return nsm_xmit_getaddr(sock, (const struct sockaddr_in6 *)sap,
+                                               program, version);
+       }
+       return 0;
+}
+
+/**
+ * nsm_xmit_notify - post an NSMPROC_NOTIFY call on a socket descriptor
+ * @sock: datagram socket descriptor
+ * @sap: pointer to socket address of peer to notify (port already filled in)
+ * @salen: length of socket address
+ * @program: RPC program number to use
+ * @mon_name: mon_name of local peer (ie the rebooting system)
+ * @state: state of local peer
+ *
+ * Send an NSMPROC_NOTIFY call to the peer at @sap using socket descriptor @sock.
+ * This request notifies the peer that we have rebooted.
+ *
+ * NB: This implementation works only over UDP, but supports both AF_INET
+ *     and AF_INET6.
+ *
+ * Returns the XID of the call, or zero if an error occurred.
+ */
+uint32_t
+nsm_xmit_notify(const int sock, const struct sockaddr *sap,
+                       const socklen_t salen, const rpcprog_t program,
+                       const char *mon_name, const int state)
+{
+       char msgbuf[NSM_MAXMSGSIZE];
+       struct stat_chge state_change;
+       struct rpc_msg mesg;
+       _Bool sent = false;
+       uint32_t xid;
+       XDR xdr;
+
+       state_change.mon_name = strdup(mon_name);
+       if (state_change.mon_name == NULL) {
+               xlog(L_ERROR, "%s: no memory", __func__);
+               return 0;
+       }
+       state_change.state = state;
+
+       xlog(D_CALL, "Sending SM_NOTIFY for %s", mon_name);
+
+       nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
+       xid = nsm_init_rpc_header(program, SM_VERS, SM_NOTIFY, &mesg);
+
+       if (xdr_callmsg(&xdr, &mesg) == TRUE &&
+           xdr_stat_chge(&xdr, &state_change) == TRUE)
+               sent = nsm_rpc_sendto(sock, sap, salen, &xdr, msgbuf);
+       else
+               xlog(L_ERROR, "%s: can't encode NSMPROC_NOTIFY call",
+                               __func__);
+
+       xdr_destroy(&xdr);
+       free(state_change.mon_name);
+
+       if (sent == false)
+               return 0;
+       return xid;
+}
+
+/**
+ * nsm_xmit_nlmcall - post an unnamed call to local NLM on a socket descriptor
+ * @sock: datagram socket descriptor
+ * @sap: address/port of NLM service to contact
+ * @salen: size of @sap
+ * @m: callback data defining RPC call to make
+ * @state: state of rebooting host
+ *
+ * Send an unnamed call (previously requested via NSMPROC_MON) to the
+ * specified local UDP-based RPC service using socket descriptor @sock.
+ *
+ * NB: This implementation works only over UDP, but supports both AF_INET
+ *     and AF_INET6.
+ *
+ * Returns the XID of the call, or zero if an error occurred.
+ */
+uint32_t
+nsm_xmit_nlmcall(const int sock, const struct sockaddr *sap,
+                       const socklen_t salen, const struct mon *m,
+                       const int state)
+{
+       const struct my_id *id = &m->mon_id.my_id;
+       char msgbuf[NSM_MAXMSGSIZE];
+       struct status new_status;
+       struct rpc_msg mesg;
+       _Bool sent = false;
+       uint32_t xid;
+       XDR xdr;
+
+       xlog(D_CALL, "Sending NLM downcall for %s", m->mon_id.mon_name);
+
+       nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
+       xid = nsm_init_rpc_header((rpcprog_t)id->my_prog,
+                                       (rpcvers_t)id->my_vers,
+                                       (rpcproc_t)id->my_proc, &mesg);
+
+       new_status.mon_name = m->mon_id.mon_name;
+       new_status.state = state;
+       memcpy(&new_status.priv, &m->priv, sizeof(new_status.priv));
+
+       if (xdr_callmsg(&xdr, &mesg) == TRUE &&
+           xdr_status(&xdr, &new_status) == TRUE)
+               sent = nsm_rpc_sendto(sock, sap, salen, &xdr, msgbuf);
+       else
+               xlog(L_ERROR, "%s: can't encode NLM downcall", __func__);
+
+       xdr_destroy(&xdr);
+
+       if (sent == false)
+               return 0;
+       return xid;
+}
+
+/**
+ * nsm_parse_reply - parse and validate the header in an RPC reply
+ * @xdrs: pointer to XDR
+ *
+ * Returns the XID of the reply, or zero if an error occurred.
+ */
+uint32_t
+nsm_parse_reply(XDR *xdrs)
+{
+       struct rpc_msg mesg = {
+               .rm_reply.rp_acpt.ar_results.proc       = (xdrproc_t)xdr_void,
+       };
+       uint32_t xid;
+
+       if (xdr_replymsg(xdrs, &mesg) == FALSE) {
+               xlog(L_ERROR, "%s: can't decode RPC reply", __func__);
+               return 0;
+       }
+       xid = (uint32_t)mesg.rm_xid;
+
+       if (mesg.rm_reply.rp_stat != MSG_ACCEPTED) {
+               xlog(L_ERROR, "%s: [0x%x] RPC status %d",
+                       __func__, xid, mesg.rm_reply.rp_stat);
+               return 0;
+       }
+
+       if (mesg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
+               xlog(L_ERROR, "%s: [0x%x] RPC accept status %d",
+                       __func__, xid, mesg.rm_reply.rp_acpt.ar_stat);
+               return 0;
+       }
+
+       return xid;
+}
+
+/**
+ * nsm_recv_getport - parse PMAP_GETPORT reply
+ * @xdrs: pointer to XDR
+ *
+ * Returns the port number from the RPC reply, or zero
+ * if an error occurred.
+ */
+unsigned long
+nsm_recv_getport(XDR *xdrs)
+{
+       unsigned long port = 0;
+
+       if (xdr_u_long(xdrs, &port) == FALSE)
+               xlog(L_ERROR, "%s: can't decode pmap reply",
+                       __func__);
+       if (port > UINT16_MAX) {
+               xlog(L_ERROR, "%s: bad port number",
+                       __func__);
+               port = 0;
+       }
+
+       xlog(D_CALL, "Received PMAP_GETPORT result: %lu", port);
+       return port;
+}
+
+/**
+ * nsm_recv_getaddr - parse RPCB_GETADDR reply
+ * @xdrs: pointer to XDR
+ *
+ * Returns the port number from the RPC reply, or zero
+ * if an error occurred.
+ */
+uint16_t
+nsm_recv_getaddr(XDR *xdrs)
+{
+       char *uaddr = NULL;
+       int port;
+
+       if (xdr_wrapstring(xdrs, &uaddr) == FALSE)
+               xlog(L_ERROR, "%s: can't decode rpcb reply",
+                       __func__);
+
+       if ((uaddr == NULL) || (uaddr[0] == '\0')) {
+               xlog(D_CALL, "Received RPCB_GETADDR result: "
+                               "program not registered");
+               return 0;
+       }
+
+       port = nfs_universal2port(uaddr);
+
+       xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
+
+       if (port < 0 || port > UINT16_MAX) {
+               xlog(L_ERROR, "%s: bad port number",
+                       __func__);
+               return 0;
+       }
+
+       xlog(D_CALL, "Received RPCB_GETADDR result: %d", port);
+       return (uint16_t)port;
+}
+
+/**
+ * nsm_recv_rpcbind - parse rpcbind reply
+ * @af: address family of reply
+ * @xdrs: pointer to XDR
+ *
+ * Returns the port number from the RPC reply, or zero
+ * if an error occurred.
+ */
+uint16_t
+nsm_recv_rpcbind(const sa_family_t family, XDR *xdrs)
+{
+       switch (family) {
+       case AF_INET:
+               return (uint16_t)nsm_recv_getport(xdrs);
+       case AF_INET6:
+               return nsm_recv_getaddr(xdrs);
+       }
+       return 0;
+}
diff --git a/support/nsm/sm_inter.x b/support/nsm/sm_inter.x
new file mode 100644 (file)
index 0000000..d8e0ad7
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 1986 Sun Microsystems, Inc.
+ * Modified by Jeffrey A. Uphoff, 1995, 1997-1999.
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - 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.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ */
+
+/*
+ * Status monitor protocol specification
+ */
+
+#ifdef RPC_CLNT
+%#include <string.h>
+#endif
+
+program SM_PROG { 
+       version SM_VERS  {
+               /* res_stat = stat_succ if status monitor agrees to monitor */
+               /* res_stat = stat_fail if status monitor cannot monitor */
+               /* if res_stat == stat_succ, state = state number of site sm_name */
+               struct sm_stat_res                       SM_STAT(struct sm_name) = 1;
+
+               /* res_stat = stat_succ if status monitor agrees to monitor */
+               /* res_stat = stat_fail if status monitor cannot monitor */
+               /* stat consists of state number of local site */
+               struct sm_stat_res                       SM_MON(struct mon) = 2;
+
+               /* stat consists of state number of local site */
+               struct sm_stat                           SM_UNMON(struct mon_id) = 3;
+
+               /* stat consists of state number of local site */
+               struct sm_stat                           SM_UNMON_ALL(struct my_id) = 4;
+
+               void                                     SM_SIMU_CRASH(void) = 5;
+
+               void                                     SM_NOTIFY(struct stat_chge) = 6;
+
+       } = 1;
+} = 100024;
+
+const  SM_MAXSTRLEN = 1024;
+const  SM_PRIV_SIZE = 16;
+
+struct sm_name {
+       string mon_name<SM_MAXSTRLEN>;
+};
+
+struct my_id {
+       string   my_name<SM_MAXSTRLEN>;         /* name of the site iniates the monitoring request*/
+       int     my_prog;                        /* rpc program # of the requesting process */
+       int     my_vers;                        /* rpc version # of the requesting process */
+       int     my_proc;                        /* rpc procedure # of the requesting process */
+};
+
+struct mon_id {
+       string  mon_name<SM_MAXSTRLEN>;         /* name of the site to be monitored */
+       struct my_id my_id;
+};
+
+
+struct mon {
+       struct mon_id mon_id;
+       opaque priv[SM_PRIV_SIZE];              /* private information to store at monitor for requesting process */
+};
+
+struct stat_chge {
+       string  mon_name<SM_MAXSTRLEN>;         /* name of the site that had the state change */
+       int     state;
+};
+
+/*
+ * state # of status monitor monitonically increases each time
+ * status of the site changes:
+ * an even number (>= 0) indicates the site is down and
+ * an odd number (> 0) indicates the site is up;
+ */
+struct sm_stat {
+       int state;              /* state # of status monitor */
+};
+
+enum res {
+       stat_succ = 0,          /* status monitor agrees to monitor */
+       stat_fail = 1           /* status monitor cannot monitor */
+};
+
+struct sm_stat_res {
+       res res_stat;
+       int state;
+};
+
+/* 
+ * structure of the status message sent back by the status monitor
+ * when monitor site status changes
+ */
+struct status {
+       string mon_name<SM_MAXSTRLEN>;
+       int state;
+       opaque priv[SM_PRIV_SIZE]; /* stored private information */
+};
+
+%#define SM_INTER_X
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644 (file)
index 0000000..faa8197
--- /dev/null
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+check_PROGRAMS = statdb_dump
+statdb_dump_SOURCES = statdb_dump.c
+
+statdb_dump_LDADD = ../support/nfs/libnfs.a \
+                   ../support/nsm/libnsm.a $(LIBCAP)
+
+SUBDIRS = nsm_client
+
+MAINTAINERCLEANFILES = Makefile.in
+
+TESTS = t0001-statd-basic-mon-unmon.sh
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644 (file)
index 0000000..8f4c9b5
--- /dev/null
@@ -0,0 +1,781 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = statdb_dump$(EXEEXT)
+subdir = tests
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
+       $(top_srcdir)/aclocal/ipv6.m4 \
+       $(top_srcdir)/aclocal/kerberos5.m4 \
+       $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
+       $(top_srcdir)/aclocal/libevent.m4 \
+       $(top_srcdir)/aclocal/libnfsidmap.m4 \
+       $(top_srcdir)/aclocal/librpcsecgss.m4 \
+       $(top_srcdir)/aclocal/libtirpc.m4 \
+       $(top_srcdir)/aclocal/nfs-utils.m4 \
+       $(top_srcdir)/aclocal/rpcsec_vers.m4 \
+       $(top_srcdir)/aclocal/tcp-wrappers.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/support/include/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_statdb_dump_OBJECTS = statdb_dump.$(OBJEXT)
+statdb_dump_OBJECTS = $(am_statdb_dump_OBJECTS)
+am__DEPENDENCIES_1 =
+statdb_dump_DEPENDENCIES = ../support/nfs/libnfs.a \
+       ../support/nsm/libnsm.a $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = $(statdb_dump_SOURCES)
+DIST_SOURCES = $(statdb_dump_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+       $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+       distdir
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+GSSD = @GSSD@
+GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@
+GSSGLUE_LIBS = @GSSGLUE_LIBS@
+HAVE_LIBWRAP = @HAVE_LIBWRAP@
+HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@
+IDMAPD = @IDMAPD@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+K5VERS = @K5VERS@
+KRBCFLAGS = @KRBCFLAGS@
+KRBDIR = @KRBDIR@
+KRBLDFLAGS = @KRBLDFLAGS@
+KRBLIBS = @KRBLIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBLKID = @LIBBLKID@
+LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBTOOL = @LIBTOOL@
+LIBWRAP = @LIBWRAP@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+RELEASE = @RELEASE@
+RPCGEN_PATH = @RPCGEN_PATH@
+RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@
+RPCSECGSS_LIBS = @RPCSECGSS_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SVCGSSD = @SVCGSSD@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_gss = @enable_gss@
+enable_ipv6 = @enable_ipv6@
+enable_mountconfig = @enable_mountconfig@
+enable_nfsv3 = @enable_nfsv3@
+enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+kprefix = @kprefix@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mountfile = @mountfile@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+startstatd = @startstatd@
+statduser = @statduser@
+statedir = @statedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+statdb_dump_SOURCES = statdb_dump.c
+statdb_dump_LDADD = ../support/nfs/libnfs.a \
+                   ../support/nsm/libnsm.a $(LIBCAP)
+
+SUBDIRS = nsm_client
+MAINTAINERCLEANFILES = Makefile.in
+TESTS = t0001-statd-basic-mon-unmon.sh
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+       @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+statdb_dump$(EXEEXT): $(statdb_dump_OBJECTS) $(statdb_dump_DEPENDENCIES) 
+       @rm -f statdb_dump$(EXEEXT)
+       $(LINK) $(statdb_dump_OBJECTS) $(statdb_dump_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statdb_dump.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+       @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+       srcdir=$(srcdir); export srcdir; \
+       list=' $(TESTS) '; \
+       $(am__tty_colors); \
+       if test -n "$$list"; then \
+         for tst in $$list; do \
+           if test -f ./$$tst; then dir=./; \
+           elif test -f $$tst; then dir=; \
+           else dir="$(srcdir)/"; fi; \
+           if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *[\ \     ]$$tst[\ \      ]*) \
+               xpass=`expr $$xpass + 1`; \
+               failed=`expr $$failed + 1`; \
+               col=$$red; res=XPASS; \
+             ;; \
+             *) \
+               col=$$grn; res=PASS; \
+             ;; \
+             esac; \
+           elif test $$? -ne 77; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *[\ \     ]$$tst[\ \      ]*) \
+               xfail=`expr $$xfail + 1`; \
+               col=$$lgn; res=XFAIL; \
+             ;; \
+             *) \
+               failed=`expr $$failed + 1`; \
+               col=$$red; res=FAIL; \
+             ;; \
+             esac; \
+           else \
+             skip=`expr $$skip + 1`; \
+             col=$$blu; res=SKIP; \
+           fi; \
+           echo "$${col}$$res$${std}: $$tst"; \
+         done; \
+         if test "$$all" -eq 1; then \
+           tests="test"; \
+           All=""; \
+         else \
+           tests="tests"; \
+           All="All "; \
+         fi; \
+         if test "$$failed" -eq 0; then \
+           if test "$$xfail" -eq 0; then \
+             banner="$$All$$all $$tests passed"; \
+           else \
+             if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+             banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+           fi; \
+         else \
+           if test "$$xpass" -eq 0; then \
+             banner="$$failed of $$all $$tests failed"; \
+           else \
+             if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+             banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+           fi; \
+         fi; \
+         dashes="$$banner"; \
+         skipped=""; \
+         if test "$$skip" -ne 0; then \
+           if test "$$skip" -eq 1; then \
+             skipped="($$skip test was not run)"; \
+           else \
+             skipped="($$skip tests were not run)"; \
+           fi; \
+           test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$skipped"; \
+         fi; \
+         report=""; \
+         if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+           report="Please report to $(PACKAGE_BUGREPORT)"; \
+           test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$report"; \
+         fi; \
+         dashes=`echo "$$dashes" | sed s/./=/g`; \
+         if test "$$failed" -eq 0; then \
+           echo "$$grn$$dashes"; \
+         else \
+           echo "$$red$$dashes"; \
+         fi; \
+         echo "$$banner"; \
+         test -z "$$skipped" || echo "$$skipped"; \
+         test -z "$$report" || echo "$$report"; \
+         echo "$$dashes$$std"; \
+         test "$$failed" -eq 0; \
+       else :; fi
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test -d "$(distdir)/$$subdir" \
+           || $(MKDIR_P) "$(distdir)/$$subdir" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+       $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+       mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \
+       ctags-recursive install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am check check-TESTS check-am clean \
+       clean-checkPROGRAMS clean-generic clean-libtool ctags \
+       ctags-recursive distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs installdirs-am maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags tags-recursive uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/nsm_client/Makefile.am b/tests/nsm_client/Makefile.am
new file mode 100644 (file)
index 0000000..4bf0a45
--- /dev/null
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+GENFILES_CLNT  = nlm_sm_inter_clnt.c
+GENFILES_SVC   = nlm_sm_inter_svc.c
+GENFILES_XDR   = nlm_sm_inter_xdr.c
+GENFILES_H     = nlm_sm_inter.h
+
+GENFILES       = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
+
+
+check_PROGRAMS = nsm_client
+nsm_client_SOURCES = $(GENFILES) nsm_client.c
+
+BUILT_SOURCES = $(GENFILES)
+nsm_client_LDADD = ../../support/nfs/libnfs.a \
+                  ../../support/nsm/libnsm.a $(LIBCAP)
+
+if CONFIG_RPCGEN
+RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
+$(RPCGEN):
+       make -C ../../tools/rpcgen all
+else
+RPCGEN = @RPCGEN_PATH@
+endif
+
+$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -l -o $@ $<
+
+$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -m -o $@ $<
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -h -o $@ $<
+
+MAINTAINERCLEANFILES = Makefile.in
+
+CLEANFILES = $(GENFILES)
+
diff --git a/tests/nsm_client/Makefile.in b/tests/nsm_client/Makefile.in
new file mode 100644 (file)
index 0000000..77b99e8
--- /dev/null
@@ -0,0 +1,573 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = nsm_client$(EXEEXT)
+subdir = tests/nsm_client
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
+       $(top_srcdir)/aclocal/ipv6.m4 \
+       $(top_srcdir)/aclocal/kerberos5.m4 \
+       $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
+       $(top_srcdir)/aclocal/libevent.m4 \
+       $(top_srcdir)/aclocal/libnfsidmap.m4 \
+       $(top_srcdir)/aclocal/librpcsecgss.m4 \
+       $(top_srcdir)/aclocal/libtirpc.m4 \
+       $(top_srcdir)/aclocal/nfs-utils.m4 \
+       $(top_srcdir)/aclocal/rpcsec_vers.m4 \
+       $(top_srcdir)/aclocal/tcp-wrappers.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/support/include/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__objects_1 = nlm_sm_inter_clnt.$(OBJEXT)
+am__objects_2 = nlm_sm_inter_svc.$(OBJEXT)
+am__objects_3 = nlm_sm_inter_xdr.$(OBJEXT)
+am__objects_4 =
+am__objects_5 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+       $(am__objects_4)
+am_nsm_client_OBJECTS = $(am__objects_5) nsm_client.$(OBJEXT)
+nsm_client_OBJECTS = $(am_nsm_client_OBJECTS)
+am__DEPENDENCIES_1 =
+nsm_client_DEPENDENCIES = ../../support/nfs/libnfs.a \
+       ../../support/nsm/libnsm.a $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = $(nsm_client_SOURCES)
+DIST_SOURCES = $(nsm_client_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+GSSD = @GSSD@
+GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@
+GSSGLUE_LIBS = @GSSGLUE_LIBS@
+HAVE_LIBWRAP = @HAVE_LIBWRAP@
+HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@
+IDMAPD = @IDMAPD@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+K5VERS = @K5VERS@
+KRBCFLAGS = @KRBCFLAGS@
+KRBDIR = @KRBDIR@
+KRBLDFLAGS = @KRBLDFLAGS@
+KRBLIBS = @KRBLIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBLKID = @LIBBLKID@
+LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBTOOL = @LIBTOOL@
+LIBWRAP = @LIBWRAP@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+RELEASE = @RELEASE@
+RPCGEN_PATH = @RPCGEN_PATH@
+RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@
+RPCSECGSS_LIBS = @RPCSECGSS_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SVCGSSD = @SVCGSSD@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_gss = @enable_gss@
+enable_ipv6 = @enable_ipv6@
+enable_mountconfig = @enable_mountconfig@
+enable_nfsv3 = @enable_nfsv3@
+enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+kprefix = @kprefix@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mountfile = @mountfile@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+startstatd = @startstatd@
+statduser = @statduser@
+statedir = @statedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+GENFILES_CLNT = nlm_sm_inter_clnt.c
+GENFILES_SVC = nlm_sm_inter_svc.c
+GENFILES_XDR = nlm_sm_inter_xdr.c
+GENFILES_H = nlm_sm_inter.h
+GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
+nsm_client_SOURCES = $(GENFILES) nsm_client.c
+BUILT_SOURCES = $(GENFILES)
+nsm_client_LDADD = ../../support/nfs/libnfs.a \
+                  ../../support/nsm/libnsm.a $(LIBCAP)
+
+@CONFIG_RPCGEN_FALSE@RPCGEN = @RPCGEN_PATH@
+@CONFIG_RPCGEN_TRUE@RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = $(GENFILES)
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/nsm_client/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu tests/nsm_client/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+       @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+nsm_client$(EXEEXT): $(nsm_client_OBJECTS) $(nsm_client_DEPENDENCIES) 
+       @rm -f nsm_client$(EXEEXT)
+       $(LINK) $(nsm_client_OBJECTS) $(nsm_client_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nlm_sm_inter_clnt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nlm_sm_inter_svc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nlm_sm_inter_xdr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsm_client.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean \
+       clean-checkPROGRAMS clean-generic clean-libtool ctags \
+       distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am
+
+@CONFIG_RPCGEN_TRUE@$(RPCGEN):
+@CONFIG_RPCGEN_TRUE@   make -C ../../tools/rpcgen all
+
+$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -l -o $@ $<
+
+$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -m -o $@ $<
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+       test -f $@ && rm -rf $@ || true
+       $(RPCGEN) -h -o $@ $<
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/nsm_client/README b/tests/nsm_client/README
new file mode 100644 (file)
index 0000000..85379dd
--- /dev/null
@@ -0,0 +1,12 @@
+The nsm_client program is intended for testing statd. It has the ability
+to act as a synthetic NSM client for sending artificial NSM calls to any
+host you choose.
+
+It also has an NLM simulator that implements the call that statd uses to
+communicate with lockd. The daemon simulator will start itself up,
+register as an NLM service and listen for "downcalls" from statd. When
+it gets one, it will log a message.
+
+Note that lockd will need to be down when using the daemon simulator. It
+also does not implement the entire NLM protocol and is only really
+useful for testing statd's downcall.
diff --git a/tests/nsm_client/nlm_sm_inter.x b/tests/nsm_client/nlm_sm_inter.x
new file mode 100644 (file)
index 0000000..95fa326
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ * Modified by Jeff Layton, 2010.
+ *
+ * NLM similator for Linux
+ */
+
+#ifdef RPC_CLNT
+%#include <string.h>
+#endif
+
+/*
+ * statd rejects monitor registrations for any non-lockd services, so pretend
+ * to be lockd when testing. Furthermore, the only call we care about from
+ * statd is #16, which is the downcall to notify the kernel of a host's status
+ * change.
+ */
+program NLM_SM_PROG {
+       /* version 3 of the NLM protocol */
+       version NLM_SM_VERS3 {
+               void     NLM_SM_NOTIFY(struct nlm_sm_notify) = 16;
+       } = 3;
+
+       /* version 2 of NLM protocol */
+       version NLM_SM_VERS4 {
+               void     NLM_SM_NOTIFY(struct nlm_sm_notify) = 16;
+       } = 4;
+} = 100021;
+
+const  SM_MAXSTRLEN = 1024;
+const  SM_PRIV_SIZE = 16;
+
+/*
+ * structure of the status message sent back by the status monitor
+ * when monitor site status changes
+ */
+struct nlm_sm_notify {
+       string mon_name<SM_MAXSTRLEN>;
+       int state;
+       opaque priv[SM_PRIV_SIZE]; /* stored private information */
+};
diff --git a/tests/nsm_client/nsm_client.c b/tests/nsm_client/nsm_client.c
new file mode 100644 (file)
index 0000000..0d1159a
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * nsm_client.c -- synthetic client and lockd simulator for testing statd
+ *
+ * Copyright (C) 2010  Red Hat, Jeff Layton <jlayton@redhat.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Very loosely based on "simulator.c" in the statd directory. Original
+ * copyright for that program follows:
+ *
+ * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <signal.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcmisc.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "nfslib.h"
+#include "nfsrpc.h"
+#include "nsm.h"
+#include "sm_inter.h"
+#include "nlm_sm_inter.h"
+#include "sockaddr.h"
+#include "xcommon.h"
+
+static void daemon_simulator(void);
+static void sim_killer(int sig);
+static int nsm_client_crash(char *);
+static int nsm_client_mon(char *, char *, char *, char *, int, int);
+static int nsm_client_stat(char *, char *);
+static int nsm_client_notify(char *, char *, char *);
+static int nsm_client_unmon(char *, char *, char *, int, int);
+static int nsm_client_unmon_all(char *, char *, int, int);
+
+extern void nlm_sm_prog_4(struct svc_req *rqstp, register SVCXPRT *transp);
+extern void svc_exit(void);
+
+/*
+ * default to 15 retransmit interval, which seems to be the default for
+ * UDP clients w/ legacy glibc RPC
+ */
+static struct timeval retrans_interval =
+{
+       .tv_sec = 15,
+};
+
+static struct option longopts[] =
+{
+       { "help", 0, 0, 'h' },
+       { "host", 0, 0, 'H' },
+       { "name", 1, 0, 'n' },
+       { "program", 1, 0, 'P' },
+       { "version", 1, 0, 'v' },
+       { NULL, 0, 0, 0 },
+};
+
+static int
+usage(char *program)
+{
+       printf("Usage:\n");
+       printf("%s [options] <command> [arg]...\n", program);
+       printf("where command is one of these with the specified args:\n");
+       printf("crash\t\t\t\ttell host to simulate crash\n");
+       printf("daemon\t\t\t\t\tstart up lockd daemon simulator\n");
+       printf("notify <mon_name> <state>\tsend a reboot notification to host\n");
+       printf("stat <mon_name>\t\t\tget status of <mon_name> on host\n");
+       printf("unmon_all\t\t\ttell host to unmon everything\n");
+       printf("unmon <mon_name>\t\t\ttell host to unmon <mon_name>\n");
+       printf("mon <mon_name> <cookie>\t\ttell host to monitor <mon_name> with private <cookie>\n");
+       return 1;
+}
+
+static int
+hex2bin(char *dst, size_t dstlen, char *src)
+{
+       int i;
+       unsigned int tmp;
+
+       for (i = 0; *src && i < dstlen; i++) {
+               if (sscanf(src, "%2x", &tmp) != 1)
+                       return 0;
+               dst[i] = tmp;
+               src++;
+               if (!*src)
+                       break;
+               src++;
+       }
+
+       return 1;
+}
+
+static void
+bin2hex(char *dst, char *src, size_t srclen)
+{
+       int i;
+
+       for (i = 0; i < srclen; i++)
+               dst += sprintf(dst, "%02x", 0xff & src[i]);
+}
+
+int
+main(int argc, char **argv)
+{
+       int arg, err = 0;
+       int remaining_args;
+       char my_name[NI_MAXHOST], host[NI_MAXHOST];
+       char cookie[SM_PRIV_SIZE];
+       int my_prog = NLM_SM_PROG;
+       int my_vers = NLM_SM_VERS4;
+
+       my_name[0] = '\0';
+       host[0] = '\0';
+
+       while ((arg = getopt_long(argc, argv, "hHn:P:v:", longopts,
+                                 NULL)) != EOF) {
+               switch (arg) {
+               case 'H':
+                       strncpy(host, optarg, sizeof(host));
+               case 'n':
+                       strncpy(my_name, optarg, sizeof(my_name));
+               case 'P':
+                       my_prog = atoi(optarg);
+               case 'v':
+                       my_vers = atoi(optarg);
+               }
+       }
+
+       remaining_args = argc - optind;
+       if (remaining_args <= 0)
+               usage(argv[0]);
+
+       if (!my_name[0])
+               gethostname(my_name, sizeof(my_name));
+       if (!host[0])
+               strncpy(host, "127.0.0.1", sizeof(host));
+
+       if (!strcasecmp(argv[optind], "daemon")) {
+               daemon_simulator();
+       } else if (!strcasecmp(argv[optind], "crash")) {
+               err = nsm_client_crash(host);
+       } else if (!strcasecmp(argv[optind], "stat")) {
+               if (remaining_args < 2)
+                       usage(argv[0]);
+               err = nsm_client_stat(host, argv[optind + 2]);
+       } else if (!strcasecmp(argv[optind], "unmon_all")) {
+               err = nsm_client_unmon_all(host, my_name, my_prog, my_vers);
+       } else if (!strcasecmp(argv[optind], "unmon")) {
+               if (remaining_args < 2)
+                       usage(argv[0]);
+               err = nsm_client_unmon(host, argv[optind + 1], my_name, my_prog,
+                                       my_vers);
+       } else if (!strcasecmp(argv[optind], "notify")) {
+               if (remaining_args < 2)
+                       usage(argv[0]);
+               err = nsm_client_notify(host, argv[optind + 1],
+                                       argv[optind + 2]);
+       } else if (!strcasecmp(argv[optind], "mon")) {
+               if (remaining_args < 2)
+                       usage(argv[0]);
+
+               memset(cookie, '\0', SM_PRIV_SIZE);
+               if (!hex2bin(cookie, sizeof(cookie), argv[optind + 2])) {
+                       fprintf(stderr, "SYS:%d\n", EINVAL);
+                       printf("Unable to convert hex cookie %s to binary.\n",
+                               argv[optind + 2]);
+                       return 1;
+               }
+
+               err = nsm_client_mon(host, argv[optind + 1], cookie, my_name,
+                                       my_prog, my_vers);
+       } else {
+               err = usage(argv[0]);
+       }
+
+       return err;
+}
+
+static CLIENT *
+nsm_client_get_rpcclient(const char *node)
+{
+       unsigned short          port;
+       struct addrinfo         *ai;
+       struct addrinfo         hints = { .ai_flags     = AI_ADDRCONFIG };
+       int                     err;
+       CLIENT                  *client = NULL;
+
+#ifndef IPV6_ENABLED
+       hints.ai_family = AF_INET;
+#endif /* IPV6_ENABLED */
+
+       /* FIXME: allow support for providing port? */
+       err = getaddrinfo(node, NULL, &hints, &ai);
+       if (err) {
+               fprintf(stderr, "EAI:%d\n", err);
+               if (err == EAI_SYSTEM)
+                       fprintf(stderr, "SYS:%d\n", errno);
+               printf("Unable to translate host to address: %s\n",
+                       err == EAI_SYSTEM ? strerror(errno) :
+                       gai_strerror(err));
+               return client;
+       }
+
+       /* FIXME: allow for TCP too? */
+       port = nfs_getport(ai->ai_addr, ai->ai_addrlen, SM_PROG,
+                          SM_VERS, IPPROTO_UDP);
+       if (!port) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("Unable to determine port for service\n");
+               goto out;
+       }
+
+       nfs_set_port(ai->ai_addr, port);
+
+       client = nfs_get_rpcclient(ai->ai_addr, ai->ai_addrlen, IPPROTO_UDP,
+                                  SM_PROG, SM_VERS, &retrans_interval);
+       if (!client) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("RPC client creation failed\n");
+       }
+out:
+       freeaddrinfo(ai);
+       return client;
+}
+
+static int
+nsm_client_mon(char *calling, char *monitoring, char *cookie, char *my_name,
+               int my_prog, int my_vers)
+{
+       CLIENT *client;
+       sm_stat_res *result;
+       mon mon;
+       int err = 0;
+
+       printf("Calling %s (as %s) to monitor %s\n", calling, my_name,
+               monitoring);
+
+       if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+               return 1;
+
+       memcpy(mon.priv, cookie, SM_PRIV_SIZE);
+       mon.mon_id.my_id.my_name = my_name;
+       mon.mon_id.my_id.my_prog = my_prog;
+       mon.mon_id.my_id.my_vers = my_vers;
+       mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
+       mon.mon_id.mon_name = monitoring;
+
+       if (!(result = sm_mon_1(&mon, client))) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("%s\n", clnt_sperror(client, "sm_mon_1"));
+               err = 1;
+               goto mon_out;
+       }
+
+       printf("SM_MON request %s, state: %d\n",
+               result->res_stat == stat_succ ? "successful" : "failed",
+               result->state);
+
+       if (result->res_stat != stat_succ) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               err = 1;
+       }
+
+mon_out:
+       clnt_destroy(client);
+       return err;
+}
+
+static int
+nsm_client_unmon(char *calling, char *unmonitoring, char *my_name, int my_prog,
+               int my_vers)
+{
+       CLIENT *client;
+       sm_stat *result;
+       mon_id mon_id;
+       int err = 0;
+
+       printf("Calling %s (as %s) to unmonitor %s\n", calling, my_name,
+               unmonitoring);
+
+       if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+               return 1;
+
+       mon_id.my_id.my_name = my_name;
+       mon_id.my_id.my_prog = my_prog;
+       mon_id.my_id.my_vers = my_vers;
+       mon_id.my_id.my_proc = NLM_SM_NOTIFY;
+       mon_id.mon_name = unmonitoring;
+
+       if (!(result = sm_unmon_1(&mon_id, client))) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("%s\n", clnt_sperror(client, "sm_unmon_1"));
+               err = 1;
+               goto unmon_out;
+       }
+
+       printf("SM_UNMON state: %d\n", result->state);
+
+unmon_out:
+       clnt_destroy(client);
+       return err;
+}
+
+static int
+nsm_client_unmon_all(char *calling, char *my_name, int my_prog, int my_vers)
+{
+       CLIENT *client;
+       sm_stat *result;
+       my_id my_id;
+       int err = 0;
+
+       printf("Calling %s (as %s) to unmonitor all hosts\n", calling, my_name);
+
+       if ((client = nsm_client_get_rpcclient(calling)) == NULL) {
+               printf("RPC client creation failed\n");
+               return 1;
+       }
+
+       my_id.my_name = my_name;
+       my_id.my_prog = my_prog;
+       my_id.my_vers = my_vers;
+       my_id.my_proc = NLM_SM_NOTIFY;
+
+       if (!(result = sm_unmon_all_1(&my_id, client))) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("%s\n", clnt_sperror(client, "sm_unmon_all_1"));
+               err = 1;
+               goto unmon_all_out;
+       }
+
+       printf("SM_UNMON_ALL state: %d\n", result->state);
+
+unmon_all_out:
+       return err;
+}
+
+static int
+nsm_client_crash(char *host)
+{
+       CLIENT *client;
+
+       if ((client = nsm_client_get_rpcclient(host)) == NULL)
+               return 1;
+
+       if (!sm_simu_crash_1(NULL, client)) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("%s\n", clnt_sperror(client, "sm_simu_crash_1"));
+               return 1;
+       }
+
+       return 0;
+}
+
+static int
+nsm_client_stat(char *calling, char *monitoring)
+{
+       CLIENT *client;
+       sm_name checking;
+       sm_stat_res *result;
+
+       if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+               return 1;
+
+       checking.mon_name = monitoring;
+
+       if (!(result = sm_stat_1(&checking, client))) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("%s\n", clnt_sperror(client, "sm_stat_1"));
+               return 1;
+       }
+
+       if (result->res_stat != stat_succ) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("stat_fail from %s for %s, state: %d\n", calling,
+                       monitoring, result->state);
+               return 1;
+       }
+
+       printf("stat_succ from %s for %s, state: %d\n", calling,
+               monitoring, result->state);
+
+       return 0;
+}
+
+static int
+nsm_client_notify(char *calling, char *mon_name, char *statestr)
+{
+       CLIENT *client;
+
+       stat_chge stat_chge = { .mon_name       = mon_name };
+
+       stat_chge.state = atoi(statestr);
+
+       if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+               return 1;
+
+       if (!sm_notify_1(&stat_chge, client)) {
+               fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+               printf("%s\n", clnt_sperror(client, "sm_notify_1"));
+               return 1;
+       }
+
+       return 0;
+}
+
+static void sim_killer(int sig)
+{
+#ifdef HAVE_LIBTIRPC
+       (void) rpcb_unset(NLM_SM_PROG, NLM_SM_VERS4, NULL);
+#else
+       (void) pmap_unset(NLM_SM_PROG, NLM_SM_VERS4);
+#endif
+       exit(0);
+}
+
+static void daemon_simulator(void)
+{
+       signal(SIGHUP, sim_killer);
+       signal(SIGINT, sim_killer);
+       signal(SIGTERM, sim_killer);
+       /* FIXME: allow for different versions? */
+       nfs_svc_create("nlmsim", NLM_SM_PROG, NLM_SM_VERS4, nlm_sm_prog_4, 0);
+       svc_run();
+}
+
+void *nlm_sm_notify_4_svc(struct nlm_sm_notify *argp, struct svc_req *rqstp)
+{
+       static char *result;
+       char        priv[SM_PRIV_SIZE * 2 + 1];
+
+       bin2hex(priv, argp->priv, SM_PRIV_SIZE);
+
+       printf("state=%d:mon_name=%s:private=%s\n", argp->state,
+               argp->mon_name, priv);
+       return (void *) &result;
+}
+
+void *nlm_sm_notify_3_svc(struct nlm_sm_notify *argp, struct svc_req *rqstp)
+{
+       return nlm_sm_notify_4_svc(argp, rqstp);
+}
diff --git a/tests/statdb_dump.c b/tests/statdb_dump.c
new file mode 100644 (file)
index 0000000..92d63f2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * statdb_dump.c -- dump contents of statd's monitor DB
+ *
+ * Copyright (C) 2010  Red Hat, Jeff Layton <jlayton@redhat.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include "nsm.h"
+#include "xlog.h"
+
+static char cookiebuf[(SM_PRIV_SIZE * 2) + 1];
+static char addrbuf[INET6_ADDRSTRLEN + 1];
+
+static unsigned int
+dump_host(const char *hostname, const struct sockaddr *sa, const struct mon *m,
+         const time_t timestamp)
+{
+       int ret;
+       const char *addr;
+       const struct sockaddr_in *sin;
+       const struct sockaddr_in6 *sin6;
+
+       ret = nsm_priv_to_hex(m->priv, cookiebuf, sizeof(cookiebuf));
+       if (!ret) {
+               xlog(L_ERROR, "Unable to convert cookie to hex string.\n");
+               return ret;
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               sin = (struct sockaddr_in *)(char *)sa;
+               addr = inet_ntop(sa->sa_family, &sin->sin_addr.s_addr, addrbuf,
+                                (socklen_t)sizeof(addrbuf));
+               break;
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6 *)(char *)sa;
+               addr = inet_ntop(sa->sa_family, &sin6->sin6_addr, addrbuf,
+                                (socklen_t)sizeof(addrbuf));
+               break;
+       default:
+               xlog(L_ERROR, "Unrecognized address family: %hu\n",
+                       sa->sa_family);
+               return 0;
+       }
+
+       if (addr == NULL) {
+               xlog(L_ERROR, "Unable to convert sockaddr to string: %s\n",
+                               strerror(errno));
+               return 0;
+       }
+
+       /*
+        * Callers of this program should assume that in the future, extra
+        * fields may be added to the output. Anyone adding extra fields to
+        * the output should add them to the end of the line.
+        */
+       printf("%s %s %s %s %s %d %d %d\n",
+                       hostname, addr, cookiebuf,
+                       m->mon_id.mon_name,
+                       m->mon_id.my_id.my_name,
+                       m->mon_id.my_id.my_prog,
+                       m->mon_id.my_id.my_vers,
+                       m->mon_id.my_id.my_proc); 
+
+       return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+       xlog_syslog(0);
+       xlog_stderr(1);
+       xlog_open(argv[0]);
+       
+       nsm_load_monitor_list(dump_host);
+       return 0;
+}
diff --git a/tests/t0001-statd-basic-mon-unmon.sh b/tests/t0001-statd-basic-mon-unmon.sh
new file mode 100644 (file)
index 0000000..00127fb
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# statd_basic_mon_unmon -- test basic mon/unmon functionality with statd
+#
+# Copyright (C) 2010  Red Hat, Jeff Layton <jlayton@redhat.com>
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+. ./test-lib.sh
+
+# This test needs root privileges
+check_root
+
+start_statd
+if [ $? -ne 0 ]; then
+       echo "FAIL: problem starting statd"
+       exit 1
+fi
+
+COOKIE=`echo $$ | md5sum | cut -d' ' -f1`
+MON_NAME=`hostname`
+
+nsm_client mon $MON_NAME $COOKIE
+if [ $? -ne 0 ]; then
+       echo "FAIL: mon failed"
+       kill_statd
+       exit 1
+fi
+
+statdb_dump | grep $MON_NAME | grep -q $COOKIE
+if [ $? -ne 0 ]; then
+       echo "FAIL: monitor DB doesn't seem to contain entry"
+       kill_statd
+       exit 1
+fi
+
+nsm_client unmon $MON_NAME
+if [ $? -ne 0 ]; then
+       echo "FAIL: unmon failed"
+       kill_statd
+       exit 1
+fi
+
+kill_statd
+
diff --git a/tests/test-lib.sh b/tests/test-lib.sh
new file mode 100644 (file)
index 0000000..3d47264
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/bash
+#
+# test-lib.sh -- library of functions for nfs-utils tests
+#
+# Copyright (C) 2010  Red Hat, Jeff Layton <jlayton@redhat.com>
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+# make sure $srcdir is set and sanity check it
+srcdir=${srcdir-.}
+if [ ! -d ${srcdir} ]; then
+       echo "***ERROR***: bad installation -- \$srcdir=${srcdir}"
+       exit 1
+fi
+
+export PATH=$PATH:${srcdir}:${srcdir}/nsm_client
+
+# Some tests require root privileges. Check for them and skip the test (exit 77)
+# if the caller doesn't have them.
+check_root() {
+       if [ $EUID -ne 0 ]; then
+               echo "*** Skipping this test as it requires root privs ***"
+               exit 77
+       fi
+}
+
+# is lockd registered as a service?
+lockd_registered() {
+       rpcinfo -p | grep -q nlockmgr
+       return $?
+}
+
+# start up statd
+start_statd() {
+       rpcinfo -u 127.0.0.1 status 1 &> /dev/null
+       if [ $? -eq 0 ]; then
+               echo "***ERROR***: statd is already running and should "
+               echo "             be down when starting this test"
+               return 1
+       fi
+       $srcdir/../utils/statd/statd --no-notify
+}
+
+# shut down statd
+kill_statd() {
+       kill `cat /var/run/rpc.statd.pid`
+}
index 79aff242437722d7324209218ee91dd4ef2052f1..231b77bb8d925ca0764abf9b11c060490858433c 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -41,6 +41,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -155,6 +156,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -221,6 +223,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -306,7 +309,7 @@ clean-libtool:
 #     (which will cause the Makefiles to be regenerated when you run `make');
 # (2) otherwise, pass the desired values on the `make' command line.
 $(RECURSIVE_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -331,7 +334,7 @@ $(RECURSIVE_TARGETS):
        fi; test -z "$$fail"
 
 $(RECURSIVE_CLEAN_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
index 31e6527048fd4af5ad818abbd22eeb33b9351ff9..7afa0428f6c1d4dd7d658d441f31cc6cfc33bbe7 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -138,6 +139,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -204,6 +206,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 6b59b277207e9c5e0e3229a501be51ba9a0258d5..b5d0a134ee6a89d7cb7a6890a479b098d8c80d33 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -40,6 +40,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -114,6 +115,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -180,6 +182,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 61cc0a4ee8a9d8fdc78788f3be80b4bb73848a5e..455a88a59d7114a722ecca02a3b7e6f395510d74 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -163,6 +164,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -229,6 +231,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 5350b85d5484fe30d2aff60794002893ca61a263..4fe57a2d2f004646ee83eda6e38150cefa78f902 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -143,6 +144,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -209,6 +211,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 9340eea4c9e597a8240a658d6e853963670b8033..56d87d2d5f319db64dbaccdaac4211eeb16c8e2b 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -43,6 +43,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -158,6 +159,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -224,6 +226,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -317,7 +320,7 @@ clean-libtool:
 #     (which will cause the Makefiles to be regenerated when you run `make');
 # (2) otherwise, pass the desired values on the `make' command line.
 $(RECURSIVE_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
@@ -342,7 +345,7 @@ $(RECURSIVE_TARGETS):
        fi; test -z "$$fail"
 
 $(RECURSIVE_CLEAN_TARGETS):
-       @failcom='exit 1'; \
+       @fail= failcom='exit 1'; \
        for f in x $$MAKEFLAGS; do \
          case $$f in \
            *=* | --[!k]*);; \
index 5c8352e3d8816cf4620930a2af8eb16340e0b651..f1e0dee7d7610316ccf88453381d076d0d46ae56 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -166,6 +167,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -232,6 +234,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 593a8ebd467e1081b4f7ed4110df89712bc8c248..331e57e8cf4b5efd8a5c296f16abc4d1db64fc69 100644 (file)
@@ -13,6 +13,7 @@
 #endif
 
 #include <sys/vfs.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
index 54778cd253efbd562a35b9d781fa23fa0ce336d2..d6e9dc06a1b8ec6954487061ea6fa31993f3b893 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -43,6 +43,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -202,6 +203,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -268,6 +270,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 40a2b4d7e14d1e2e2256d9ea5950fcde1087fbe7..bd37a5f48d89f7d57a799ba833c7cfb78d7511bd 100644 (file)
@@ -56,7 +56,6 @@
 #include "krb5_util.h"
 
 char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
-char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR;
 char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
 char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
 char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
@@ -159,11 +158,6 @@ main(int argc, char *argv[])
        if (preferred_realm == NULL)
                gssd_k5_get_default_realm(&preferred_realm);
 
-       snprintf(pipefs_nfsdir, sizeof(pipefs_nfsdir), "%s/%s",
-                pipefs_dir, GSSD_SERVICE_NAME);
-       if (pipefs_nfsdir[sizeof(pipefs_nfsdir)-1] != '\0')
-               errx(1, "pipefs_nfsdir path name too long");
-
        if ((progname = strrchr(argv[0], '/')))
                progname++;
        else
index 3c52f46699de9ee1bd2ddcd6388f460b17ebf943..465c305f17da92dc06920d77f03ff4986850cfcd 100644 (file)
@@ -60,7 +60,6 @@ enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY};
 
 
 extern char                    pipefs_dir[PATH_MAX];
-extern char                    pipefs_nfsdir[PATH_MAX];
 extern char                    keytabfile[PATH_MAX];
 extern char                    *ccachesearch[];
 extern int                     use_memcache;
@@ -83,13 +82,24 @@ struct clnt_info {
        int                     krb5_poll_index;
        int                     spkm3_fd;
        int                     spkm3_poll_index;
+       int                     gssd_fd;
+       int                     gssd_poll_index;
        struct sockaddr_storage addr;
 };
 
+TAILQ_HEAD(topdirs_list_head, topdirs_info) topdirs_list;
+
+struct topdirs_info {
+       TAILQ_ENTRY(topdirs_info)   list;
+       char                    *dirname;
+       int                     fd;
+};
+
 void init_client_list(void);
 int update_client_list(void);
 void handle_krb5_upcall(struct clnt_info *clp);
 void handle_spkm3_upcall(struct clnt_info *clp);
+void handle_gssd_upcall(struct clnt_info *clp);
 int gssd_acquire_cred(char *server_name);
 void gssd_run(void);
 
index 917b66221bfd536419146f1881b293a2831bf406..f1a68d3473550663bd3964aab4bdfe4c53a3e88a 100644 (file)
@@ -49,6 +49,7 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <unistd.h>
+#include <dirent.h>
 
 #include "gssd.h"
 #include "err_util.h"
@@ -73,6 +74,17 @@ scan_poll_results(int ret)
 
        for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
        {
+               i = clp->gssd_poll_index;
+               if (i >= 0 && pollarray[i].revents) {
+                       if (pollarray[i].revents & POLLHUP)
+                               dir_changed = 1;
+                       if (pollarray[i].revents & POLLIN)
+                               handle_gssd_upcall(clp);
+                       pollarray[clp->gssd_poll_index].revents = 0;
+                       ret--;
+                       if (!ret)
+                               break;
+               }
                i = clp->krb5_poll_index;
                if (i >= 0 && pollarray[i].revents) {
                        if (pollarray[i].revents & POLLHUP)
@@ -98,12 +110,85 @@ scan_poll_results(int ret)
        }
 };
 
+static int
+topdirs_add_entry(struct dirent *dent)
+{
+       struct topdirs_info *tdi;
+
+       tdi = calloc(sizeof(struct topdirs_info), 1);
+       if (tdi == NULL) {
+               printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
+               return -1;
+       }
+       tdi->dirname = malloc(PATH_MAX);
+       if (tdi->dirname == NULL) {
+               printerr(0, "ERROR: Couldn't allocate directory name\n");
+               free(tdi);
+               return -1;
+       }
+       snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
+       tdi->fd = open(tdi->dirname, O_RDONLY);
+       if (tdi->fd != -1) {
+               fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
+               fcntl(tdi->fd, F_NOTIFY,
+                     DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+       }
+
+       TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
+       return 0;
+}
+
+static void
+topdirs_free_list(void)
+{
+       struct topdirs_info *tdi;
+
+       TAILQ_FOREACH(tdi, &topdirs_list, list) {
+               free(tdi->dirname);
+               if (tdi->fd != -1)
+                       close(tdi->fd);
+               TAILQ_REMOVE(&topdirs_list, tdi, list);
+               free(tdi);
+       }
+}
+
+static int
+topdirs_init_list(void)
+{
+       DIR             *pipedir;
+       struct dirent   *dent;
+       int             ret;
+
+       TAILQ_INIT(&topdirs_list);
+
+       pipedir = opendir(pipefs_dir);
+       if (pipedir == NULL) {
+               printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
+                        "%s\n", pipefs_dir, strerror(errno));
+               return -1;
+       }
+       for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
+               if (dent->d_type != DT_DIR ||
+                   strcmp(dent->d_name, ".") == 0  ||
+                   strcmp(dent->d_name, "..") == 0) {
+                       continue;
+               }
+               ret = topdirs_add_entry(dent);
+               if (ret)
+                       goto out_err;
+       }
+       closedir(pipedir);
+       return 0;
+out_err:
+       topdirs_free_list();
+       return -1;
+}
+
 void
 gssd_run()
 {
        int                     ret;
        struct sigaction        dn_act;
-       int                     fd;
        sigset_t                set;
 
        /* Taken from linux/Documentation/dnotify.txt: */
@@ -117,13 +202,8 @@ gssd_run()
        sigaddset(&set, DNOTIFY_SIGNAL);
        sigprocmask(SIG_UNBLOCK, &set, NULL);
 
-       if ((fd = open(pipefs_nfsdir, O_RDONLY)) == -1) {
-               printerr(0, "ERROR: failed to open %s: %s\n",
-                        pipefs_nfsdir, strerror(errno));
-               exit(1);
-       }
-       fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL);
-       fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+       if (topdirs_init_list() != 0)
+               return;
 
        init_client_list();
 
@@ -132,8 +212,7 @@ gssd_run()
                while (dir_changed) {
                        dir_changed = 0;
                        if (update_client_list()) {
-                               printerr(0, "ERROR: couldn't update "
-                                        "client list\n");
+                               /* Error msg is already printed */
                                exit(1);
                        }
                }
@@ -151,6 +230,7 @@ gssd_run()
                        scan_poll_results(ret);
                }
        }
-       close(fd);
+       topdirs_free_list();
+
        return;
 }
index 37e2aa512f3fc6783bb34bb4eede9a15bcb99243..be4fb1150e1582990240a9213bb8fe5b9291e481 100644 (file)
@@ -73,6 +73,7 @@
 #include "krb5_util.h"
 #include "context.h"
 #include "nfsrpc.h"
+#include "nfslib.h"
 
 /*
  * pollarray:
  *      linked list of struct clnt_info which associates a clntXXX directory
  *     with an index into pollarray[], and other basic data about that client.
  *
- * Directory structure: created by the kernel nfs client
- *      {pipefs_nfsdir}/clntXX             : one per rpc_clnt struct in the kernel
- *      {pipefs_nfsdir}/clntXX/krb5        : read uid for which kernel wants
+ * Directory structure: created by the kernel
+ *      {rpc_pipefs}/{dir}/clntXX         : one per rpc_clnt struct in the kernel
+ *      {rpc_pipefs}/{dir}/clntXX/krb5    : read uid for which kernel wants
  *                                         a context, write the resulting context
- *      {pipefs_nfsdir}/clntXX/info        : stores info such as server name
+ *      {rpc_pipefs}/{dir}/clntXX/info    : stores info such as server name
+ *      {rpc_pipefs}/{dir}/clntXX/gssd    : pipe for all gss mechanisms using
+ *                                         a text-based string of parameters
  *
  * Algorithm:
- *      Poll all {pipefs_nfsdir}/clntXX/krb5 files.  When ready, data read
- *      is a uid; performs rpcsec_gss context initialization protocol to
+ *      Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files.  When data is ready,
+ *      read and process; performs rpcsec_gss context initialization protocol to
  *      get a cred for that user.  Writes result to corresponding krb5 file
  *      in a form the kernel code will understand.
  *      In addition, we make sure we are notified whenever anything is
- *      created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
- *      and rescan the whole {pipefs_nfsdir} when this happens.
+ *      created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
+ *      and rescan the whole {rpc_pipefs} when this happens.
  */
 
 struct pollfd * pollarray;
@@ -105,7 +108,7 @@ int pollsize;  /* the size of pollaray (in pollfd's) */
 
 /*
  * convert a presentation address string to a sockaddr_storage struct. Returns
- * true on success and false on failure.
+ * true on success or false on failure.
  *
  * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
  * gssd nececessarily relies on hostname resolution and DNS AAAA records
@@ -117,26 +120,43 @@ int pollsize;  /* the size of pollaray (in pollfd's) */
  * not really feasible at present.
  */
 static int
-addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port)
+addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
 {
-       struct sockaddr_in      *s4 = (struct sockaddr_in *) sa;
-#ifdef IPV6_SUPPORTED
-       struct sockaddr_in6     *s6 = (struct sockaddr_in6 *) sa;
-#endif /* IPV6_SUPPORTED */
+       int rc;
+       struct addrinfo *res;
+       struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
 
-       if (inet_pton(AF_INET, addr, &s4->sin_addr)) {
-               s4->sin_family = AF_INET;
-               s4->sin_port = htons(port);
-#ifdef IPV6_SUPPORTED
-       } else if (inet_pton(AF_INET6, addr, &s6->sin6_addr)) {
-               s6->sin6_family = AF_INET6;
-               s6->sin6_port = htons(port);
+#ifndef IPV6_SUPPORTED
+       hints.ai_family = AF_INET;
 #endif /* IPV6_SUPPORTED */
-       } else {
-               printerr(0, "ERROR: unable to convert %s to address\n", addr);
+
+       rc = getaddrinfo(node, port, &hints, &res);
+       if (rc) {
+               printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
+                        node, port, rc == EAI_SYSTEM ? strerror(errno) :
+                                               gai_strerror(rc));
                return 0;
        }
 
+#ifdef IPV6_SUPPORTED
+       /*
+        * getnameinfo ignores the scopeid. If the address turns out to have
+        * a non-zero scopeid, we can't use it -- the resolved host might be
+        * completely different from the one intended.
+        */
+       if (res->ai_addr->sa_family == AF_INET6) {
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
+               if (sin6->sin6_scope_id) {
+                       printerr(0, "ERROR: address %s has non-zero "
+                                   "sin6_scope_id!\n", node);
+                       freeaddrinfo(res);
+                       return 0;
+               }
+       }
+#endif /* IPV6_SUPPORTED */
+
+       memcpy(sa, res->ai_addr, res->ai_addrlen);
+       freeaddrinfo(res);
        return 1;
 }
 
@@ -194,11 +214,10 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
        char            program[16];
        char            version[16];
        char            protoname[16];
-       char            cb_port[128];
+       char            port[128];
        char            *p;
        int             fd = -1;
        int             numfields;
-       int             port = 0;
 
        *servicename = *servername = *protocol = NULL;
 
@@ -227,20 +246,22 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
                goto fail;
        }
 
-       cb_port[0] = '\0';
+       port[0] = '\0';
        if ((p = strstr(buf, "port")) != NULL)
-               sscanf(p, "port: %127s\n", cb_port);
+               sscanf(p, "port: %127s\n", port);
 
        /* check service, program, and version */
-       if(memcmp(service, "nfs", 3)) return -1;
+       if (memcmp(service, "nfs", 3) != 0)
+               return -1;
        *prog = atoi(program + 1); /* skip open paren */
        *vers = atoi(version);
-       if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
-               goto fail;
 
-       if (cb_port[0] != '\0') {
-               port = atoi(cb_port);
-               if (port < 0 || port > 65535)
+       if (strlen(service) == 3 ) {
+               if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
+                   (*vers != 4)))
+                       goto fail;
+       } else if (memcmp(service, "nfs4_cb", 7) == 0) {
+               if (*vers != 1)
                        goto fail;
        }
 
@@ -281,9 +302,13 @@ destroy_client(struct clnt_info *clp)
        if (clp->spkm3_poll_index != -1)
                memset(&pollarray[clp->spkm3_poll_index], 0,
                                        sizeof(struct pollfd));
+       if (clp->gssd_poll_index != -1)
+               memset(&pollarray[clp->gssd_poll_index], 0,
+                                       sizeof(struct pollfd));
        if (clp->dir_fd != -1) close(clp->dir_fd);
        if (clp->krb5_fd != -1) close(clp->krb5_fd);
        if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
+       if (clp->gssd_fd != -1) close(clp->gssd_fd);
        free(clp->dirname);
        free(clp->servicename);
        free(clp->servername);
@@ -303,8 +328,10 @@ insert_new_clnt(void)
        }
        clp->krb5_poll_index = -1;
        clp->spkm3_poll_index = -1;
+       clp->gssd_poll_index = -1;
        clp->krb5_fd = -1;
        clp->spkm3_fd = -1;
+       clp->gssd_fd = -1;
        clp->dir_fd = -1;
 
        TAILQ_INSERT_HEAD(&clnt_list, clp, list);
@@ -315,19 +342,43 @@ out:
 static int
 process_clnt_dir_files(struct clnt_info * clp)
 {
-       char    kname[32];
-       char    sname[32];
-       char    info_file_name[32];
+       char    name[PATH_MAX];
+       char    gname[PATH_MAX];
+       char    info_file_name[PATH_MAX];
 
-       if (clp->krb5_fd == -1) {
-               snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
-               clp->krb5_fd = open(kname, O_RDWR);
+       if (clp->gssd_fd == -1) {
+               snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
+               clp->gssd_fd = open(gname, O_RDWR);
        }
-       if (clp->spkm3_fd == -1) {
-               snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
-               clp->spkm3_fd = open(sname, O_RDWR);
+       if (clp->gssd_fd == -1) {
+               if (clp->krb5_fd == -1) {
+                       snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
+                       clp->krb5_fd = open(name, O_RDWR);
+               }
+               if (clp->spkm3_fd == -1) {
+                       snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
+                       clp->spkm3_fd = open(name, O_RDWR);
+               }
+
+               /* If we opened a gss-specific pipe, let's try opening
+                * the new upcall pipe again. If we succeed, close
+                * gss-specific pipe(s).
+                */
+               if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
+                       clp->gssd_fd = open(gname, O_RDWR);
+                       if (clp->gssd_fd != -1) {
+                               if (clp->krb5_fd != -1)
+                                       close(clp->krb5_fd);
+                               clp->krb5_fd = -1;
+                               if (clp->spkm3_fd != -1)
+                                       close(clp->spkm3_fd);
+                               clp->spkm3_fd = -1;
+                       }
+               }
        }
-       if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
+
+       if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
+                       (clp->gssd_fd == -1))
                return -1;
        snprintf(info_file_name, sizeof(info_file_name), "%s/info",
                        clp->dirname);
@@ -362,6 +413,15 @@ get_poll_index(int *ind)
 static int
 insert_clnt_poll(struct clnt_info *clp)
 {
+       if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
+               if (get_poll_index(&clp->gssd_poll_index)) {
+                       printerr(0, "ERROR: Too many gssd clients\n");
+                       return -1;
+               }
+               pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
+               pollarray[clp->gssd_poll_index].events |= POLLIN;
+       }
+
        if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
                if (get_poll_index(&clp->krb5_poll_index)) {
                        printerr(0, "ERROR: Too many krb5 clients\n");
@@ -384,17 +444,18 @@ insert_clnt_poll(struct clnt_info *clp)
 }
 
 static void
-process_clnt_dir(char *dir)
+process_clnt_dir(char *dir, char *pdir)
 {
        struct clnt_info *      clp;
 
        if (!(clp = insert_new_clnt()))
                goto fail_destroy_client;
 
-       if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
+       /* An extra for the '/', and an extra for the null */
+       if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
                goto fail_destroy_client;
        }
-       memcpy(clp->dirname, dir, strlen(dir));
+       sprintf(clp->dirname, "%s/%s", pdir, dir);
        if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
                printerr(0, "ERROR: can't open %s: %s\n",
                         clp->dirname, strerror(errno));
@@ -438,16 +499,24 @@ init_client_list(void)
  * directories, since the DNOTIFY could have been in there.
  */
 static void
-update_old_clients(struct dirent **namelist, int size)
+update_old_clients(struct dirent **namelist, int size, char *pdir)
 {
        struct clnt_info *clp;
        void *saveprev;
        int i, stillhere;
+       char fname[PATH_MAX];
 
        for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+               /* only compare entries in the global list that are from the
+                * same pipefs parent directory as "pdir"
+                */
+               if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
+
                stillhere = 0;
                for (i=0; i < size; i++) {
-                       if (!strcmp(clp->dirname, namelist[i]->d_name)) {
+                       snprintf(fname, sizeof(fname), "%s/%s",
+                                pdir, namelist[i]->d_name);
+                       if (strcmp(clp->dirname, fname) == 0) {
                                stillhere = 1;
                                break;
                        }
@@ -468,48 +537,69 @@ update_old_clients(struct dirent **namelist, int size)
 
 /* Search for a client by directory name, return 1 if found, 0 otherwise */
 static int
-find_client(char *dirname)
+find_client(char *dirname, char *pdir)
 {
        struct clnt_info        *clp;
+       char fname[PATH_MAX];
 
-       for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
-               if (!strcmp(clp->dirname, dirname))
+       for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+               snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
+               if (strcmp(clp->dirname, fname) == 0)
                        return 1;
+       }
        return 0;
 }
 
-/* Used to read (and re-read) list of clients, set up poll array. */
-int
-update_client_list(void)
+static int
+process_pipedir(char *pipe_name)
 {
        struct dirent **namelist;
        int i, j;
 
-       if (chdir(pipefs_nfsdir) < 0) {
+       if (chdir(pipe_name) < 0) {
                printerr(0, "ERROR: can't chdir to %s: %s\n",
-                        pipefs_nfsdir, strerror(errno));
+                        pipe_name, strerror(errno));
                return -1;
        }
 
-       j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
+       j = scandir(pipe_name, &namelist, NULL, alphasort);
        if (j < 0) {
                printerr(0, "ERROR: can't scandir %s: %s\n",
-                        pipefs_nfsdir, strerror(errno));
+                        pipe_name, strerror(errno));
                return -1;
        }
-       update_old_clients(namelist, j);
+
+       update_old_clients(namelist, j, pipe_name);
        for (i=0; i < j; i++) {
                if (i < FD_ALLOC_BLOCK
                                && !strncmp(namelist[i]->d_name, "clnt", 4)
-                               && !find_client(namelist[i]->d_name))
-                       process_clnt_dir(namelist[i]->d_name);
+                               && !find_client(namelist[i]->d_name, pipe_name))
+                       process_clnt_dir(namelist[i]->d_name, pipe_name);
                free(namelist[i]);
        }
 
        free(namelist);
+
        return 0;
 }
 
+/* Used to read (and re-read) list of clients, set up poll array. */
+int
+update_client_list(void)
+{
+       int retval = -1;
+       struct topdirs_info *tdi;
+
+       TAILQ_FOREACH(tdi, &topdirs_list, list) {
+               retval = process_pipedir(tdi->dirname);
+               if (retval)
+                       printerr(1, "WARNING: error processing %s\n",
+                                tdi->dirname);
+
+       }
+       return retval;
+}
+
 static int
 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
            gss_buffer_desc *context_token)
@@ -798,15 +888,14 @@ int create_auth_rpc_client(struct clnt_info *clp,
        goto out;
 }
 
-
 /*
  * this code uses the userland rpcsec gss library to create a krb5
  * context on behalf of the kernel
  */
-void
-handle_krb5_upcall(struct clnt_info *clp)
+static void
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
+                   char *service)
 {
-       uid_t                   uid;
        CLIENT                  *rpc_clnt = NULL;
        AUTH                    *auth = NULL;
        struct authgss_private_data pd;
@@ -815,23 +904,51 @@ handle_krb5_upcall(struct clnt_info *clp)
        char                    **ccname;
        char                    **dirname;
        int                     create_resp = -1;
+       int                     err, downcall_err = -EACCES;
 
-       printerr(1, "handling krb5 upcall\n");
+       printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
 
+       if (tgtname) {
+               if (clp->servicename) {
+                       free(clp->servicename);
+                       clp->servicename = strdup(tgtname);
+               }
+       }
        token.length = 0;
        token.value = NULL;
        memset(&pd, 0, sizeof(struct authgss_private_data));
 
-       if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
-               printerr(0, "WARNING: failed reading uid from krb5 "
-                           "upcall pipe: %s\n", strerror(errno));
-               goto out;
-       }
-
-       if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
+       /*
+        * If "service" is specified, then the kernel is indicating that
+        * we must use machine credentials for this request.  (Regardless
+        * of the uid value or the setting of root_uses_machine_creds.)
+        * If the service value is "*", then any service name can be used.
+        * Otherwise, it specifies the service name that should be used.
+        * (For now, the values of service will only be "*" or "nfs".)
+        *
+        * Restricting gssd to use "nfs" service name is needed for when
+        * the NFS server is doing a callback to the NFS client.  In this
+        * case, the NFS server has to authenticate itself as "nfs" --
+        * even if there are other service keys such as "host" or "root"
+        * in the keytab.
+        *
+        * Another case when the kernel may specify the service attribute
+        * is when gssd is being asked to create the context for a
+        * SETCLIENT_ID operation.  In this case, machine credentials
+        * must be used for the authentication.  However, the service name
+        * used for this case is not important.
+        *
+        */
+       printerr(2, "%s: service is '%s'\n", __func__,
+                service ? service : "<null>");
+       if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
+                               service == NULL)) {
                /* Tell krb5 gss which credentials cache to use */
                for (dirname = ccachesearch; *dirname != NULL; dirname++) {
-                       if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
+                       err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
+                       if (err == -EKEYEXPIRED)
+                               downcall_err = -EKEYEXPIRED;
+                       else if (!err)
                                create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
                                                             AUTHTYPE_KRB5);
                        if (create_resp == 0)
@@ -839,12 +956,13 @@ handle_krb5_upcall(struct clnt_info *clp)
                }
        }
        if (create_resp != 0) {
-               if (uid == 0 && root_uses_machine_creds == 1) {
+               if (uid == 0 && (root_uses_machine_creds == 1 ||
+                               service != NULL)) {
                        int nocache = 0;
                        int success = 0;
                        do {
                                gssd_refresh_krb5_machine_credential(clp->servername,
-                                                                    NULL, nocache);
+                                                                    NULL, service);
                                /*
                                 * Get a list of credential cache names and try each
                                 * of them until one works or we've tried them all
@@ -904,7 +1022,7 @@ handle_krb5_upcall(struct clnt_info *clp)
                goto out_return_error;
        }
 
-       do_downcall(clp->krb5_fd, uid, &pd, &token);
+       do_downcall(fd, uid, &pd, &token);
 
 out:
        if (token.value)
@@ -920,7 +1038,7 @@ out:
        return;
 
 out_return_error:
-       do_error_downcall(clp->krb5_fd, uid, -1);
+       do_error_downcall(fd, uid, downcall_err);
        goto out;
 }
 
@@ -928,26 +1046,19 @@ out_return_error:
  * this code uses the userland rpcsec gss library to create an spkm3
  * context on behalf of the kernel
  */
-void
-handle_spkm3_upcall(struct clnt_info *clp)
+static void
+process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
 {
-       uid_t                   uid;
        CLIENT                  *rpc_clnt = NULL;
        AUTH                    *auth = NULL;
        struct authgss_private_data pd;
        gss_buffer_desc         token;
 
-       printerr(2, "handling spkm3 upcall\n");
+       printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
 
        token.length = 0;
        token.value = NULL;
 
-       if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
-               printerr(0, "WARNING: failed reading uid from spkm3 "
-                        "upcall pipe: %s\n", strerror(errno));
-               goto out;
-       }
-
        if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
                printerr(0, "WARNING: Failed to create spkm3 context for "
                            "user with uid %d\n", uid);
@@ -968,7 +1079,7 @@ handle_spkm3_upcall(struct clnt_info *clp)
                goto out_return_error;
        }
 
-       do_downcall(clp->spkm3_fd, uid, &pd, &token);
+       do_downcall(fd, uid, &pd, &token);
 
 out:
        if (token.value)
@@ -980,6 +1091,139 @@ out:
        return;
 
 out_return_error:
-       do_error_downcall(clp->spkm3_fd, uid, -1);
+       do_error_downcall(fd, uid, -1);
        goto out;
 }
+
+void
+handle_krb5_upcall(struct clnt_info *clp)
+{
+       uid_t                   uid;
+
+       if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+               printerr(0, "WARNING: failed reading uid from krb5 "
+                           "upcall pipe: %s\n", strerror(errno));
+               return;
+       }
+
+       return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
+}
+
+void
+handle_spkm3_upcall(struct clnt_info *clp)
+{
+       uid_t                   uid;
+
+       if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+               printerr(0, "WARNING: failed reading uid from spkm3 "
+                        "upcall pipe: %s\n", strerror(errno));
+               return;
+       }
+
+       return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
+}
+
+void
+handle_gssd_upcall(struct clnt_info *clp)
+{
+       uid_t                   uid;
+       char                    *lbuf = NULL;
+       int                     lbuflen = 0;
+       char                    *p;
+       char                    *mech = NULL;
+       char                    *target = NULL;
+       char                    *service = NULL;
+
+       printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
+
+       if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
+               printerr(0, "WARNING: handle_gssd_upcall: "
+                           "failed reading request\n");
+               return;
+       }
+       printerr(2, "%s: '%s'\n", __func__, lbuf);
+
+       /* find the mechanism name */
+       if ((p = strstr(lbuf, "mech=")) != NULL) {
+               mech = malloc(lbuflen);
+               if (!mech)
+                       goto out;
+               if (sscanf(p, "mech=%s", mech) != 1) {
+                       printerr(0, "WARNING: handle_gssd_upcall: "
+                                   "failed to parse gss mechanism name "
+                                   "in upcall string '%s'\n", lbuf);
+                       goto out;
+               }
+       } else {
+               printerr(0, "WARNING: handle_gssd_upcall: "
+                           "failed to find gss mechanism name "
+                           "in upcall string '%s'\n", lbuf);
+               goto out;
+       }
+
+       /* read uid */
+       if ((p = strstr(lbuf, "uid=")) != NULL) {
+               if (sscanf(p, "uid=%d", &uid) != 1) {
+                       printerr(0, "WARNING: handle_gssd_upcall: "
+                                   "failed to parse uid "
+                                   "in upcall string '%s'\n", lbuf);
+                       goto out;
+               }
+       } else {
+               printerr(0, "WARNING: handle_gssd_upcall: "
+                           "failed to find uid "
+                           "in upcall string '%s'\n", lbuf);
+               goto out;
+       }
+
+       /* read target name */
+       if ((p = strstr(lbuf, "target=")) != NULL) {
+               target = malloc(lbuflen);
+               if (!target)
+                       goto out;
+               if (sscanf(p, "target=%s", target) != 1) {
+                       printerr(0, "WARNING: handle_gssd_upcall: "
+                                   "failed to parse target name "
+                                   "in upcall string '%s'\n", lbuf);
+                       goto out;
+               }
+       }
+
+       /*
+        * read the service name
+        *
+        * The presence of attribute "service=" indicates that machine
+        * credentials should be used for this request.  If the value
+        * is "*", then any machine credentials available can be used.
+        * If the value is anything else, then machine credentials for
+        * the specified service name (always "nfs" for now) should be
+        * used.
+        */
+       if ((p = strstr(lbuf, "service=")) != NULL) {
+               service = malloc(lbuflen);
+               if (!service)
+                       goto out;
+               if (sscanf(p, "service=%s", service) != 1) {
+                       printerr(0, "WARNING: handle_gssd_upcall: "
+                                   "failed to parse service type "
+                                   "in upcall string '%s'\n", lbuf);
+                       goto out;
+               }
+       }
+
+       if (strcmp(mech, "krb5") == 0)
+               process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
+       else if (strcmp(mech, "spkm3") == 0)
+               process_spkm3_upcall(clp, uid, clp->gssd_fd);
+       else
+               printerr(0, "WARNING: handle_gssd_upcall: "
+                           "received unknown gss mech '%s'\n", mech);
+
+out:
+       free(lbuf);
+       free(mech);
+       free(target);
+       free(service);
+       return; 
+}
+
index 78e9775de180b3bb5776b91ebb31a860c9992f58..1295f5776eb78bc6e6154d8e80ca111fbbe8c3a2 100644 (file)
@@ -170,9 +170,8 @@ select_krb5_ccache(const struct dirent *d)
  * what we want. Otherwise, return zero and no dirent pointer.
  * The caller is responsible for freeing the dirent if one is returned.
  *
- * Returns:
- *     0 => could not find an existing entry
- *     1 => found an existing entry
+ * Returns 0 if a valid-looking entry was found and a non-zero error
+ * code otherwise.
  */
 static int
 gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
@@ -186,7 +185,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
        char buf[1030];
        char *princname = NULL;
        char *realm = NULL;
-       int score, best_match_score = 0;
+       int score, best_match_score = 0, err = -EACCES;
 
        memset(&best_match_stat, 0, sizeof(best_match_stat));
        *d = NULL;
@@ -229,6 +228,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
                                printerr(3, "CC file '%s' is expired or corrupt\n",
                                         statname);
                                free(namelist[i]);
+                               err = -EKEYEXPIRED;
                                continue;
                        }
 
@@ -284,11 +284,12 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
                }
                free(namelist);
        }
-       if (found)
-       {
+       if (found) {
                *d = best_match_dir;
+               return 0;
        }
-       return found;
+
+       return err;
 }
 
 
@@ -797,10 +798,9 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
  */
 static int
 find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
-                 krb5_keytab_entry *kte)
+                 krb5_keytab_entry *kte, const char **svcnames)
 {
        krb5_error_code code;
-       const char *svcnames[] = { "root", "nfs", "host", NULL };
        char **realmnames = NULL;
        char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
        int i, j, retval;
@@ -1025,29 +1025,29 @@ err_cache:
  * given only a UID.  We really need more information, but we
  * do the best we can.
  *
- * Returns:
- *     0 => a ccache was found
- *     1 => no ccache was found
+ * Returns 0 if a ccache was found, and a non-zero error code otherwise.
  */
 int
 gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname)
 {
        char                    buf[MAX_NETOBJ_SZ];
        struct dirent           *d;
+       int                     err;
 
        printerr(2, "getting credentials for client with uid %u for "
                    "server %s\n", uid, servername);
        memset(buf, 0, sizeof(buf));
-       if (gssd_find_existing_krb5_ccache(uid, dirname, &d)) {
-               snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
-               free(d);
-       }
-       else
-               return 1;
+       err = gssd_find_existing_krb5_ccache(uid, dirname, &d);
+       if (err)
+               return err;
+
+       snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
+       free(d);
+
        printerr(2, "using %s as credentials cache for client with "
                    "uid %u for server %s\n", buf, uid, servername);
        gssd_set_krb5_ccache_name(buf);
-       return 0;
+       return err;
 }
 
 /*
@@ -1096,7 +1096,8 @@ gssd_get_krb5_machine_cred_list(char ***list)
        for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
                if (ple->ccname) {
                        /* Make sure cred is up-to-date before returning it */
-                       retval = gssd_refresh_krb5_machine_credential(NULL, ple, 0);
+                       retval = gssd_refresh_krb5_machine_credential(NULL, ple,
+                               NULL);
                        if (retval)
                                continue;
                        if (i + 1 > listsize) {
@@ -1186,14 +1187,24 @@ gssd_destroy_krb5_machine_creds(void)
  */
 int
 gssd_refresh_krb5_machine_credential(char *hostname,
-                                    struct gssd_k5_kt_princ *ple, int nocache)
+                                    struct gssd_k5_kt_princ *ple, 
+                                        char *service)
 {
        krb5_error_code code = 0;
        krb5_context context;
        krb5_keytab kt = NULL;;
        int retval = 0;
        char *k5err = NULL;
+       const char *svcnames[4] = { "root", "nfs", "host", NULL };
 
+       /*
+        * If a specific service name was specified, use it.
+        * Otherwise, use the default list.
+        */
+       if (service != NULL && strcmp(service, "*") != 0) {
+               svcnames[0] = service;
+               svcnames[1] = NULL;
+       }
        if (hostname == NULL && ple == NULL)
                return EINVAL;
 
@@ -1216,7 +1227,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
        if (ple == NULL) {
                krb5_keytab_entry kte;
 
-               code = find_keytab_entry(context, kt, hostname, &kte);
+               code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
                if (code) {
                        printerr(0, "ERROR: %s: no usable keytab entry found "
                                 "in keytab %s for connection with host %s\n",
@@ -1241,7 +1252,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
                        goto out;
                }
        }
-       retval = gssd_get_single_krb5_cred(context, kt, ple, nocache);
+       retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
 out:
        if (kt)
                krb5_kt_close(context, kt);
index 4b6b28119e5b0ce42518fc404221bc2e9736ba89..4602cc31d433561317ff3bcdee796d2f312e2a6b 100644 (file)
@@ -30,7 +30,8 @@ void gssd_free_krb5_machine_cred_list(char **list);
 void gssd_setup_krb5_machine_gss_ccache(char *servername);
 void gssd_destroy_krb5_machine_creds(void);
 int  gssd_refresh_krb5_machine_credential(char *hostname,
-                                         struct gssd_k5_kt_princ *ple, int nocache);
+                                         struct gssd_k5_kt_princ *ple, 
+                                         char *service);
 char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
 void gssd_k5_get_default_realm(char **def_realm);
 
index 6f2ba61e31edfc62c5b60bf379c80b0631690299..f1bfbef7b57a3b63428c3ab278e97c31966252ff 100644 (file)
@@ -56,6 +56,7 @@
 #include "gss_util.h"
 #include "err_util.h"
 #include "context.h"
+#include "gss_oids.h"
 
 extern char * mech2file(gss_OID mech);
 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
@@ -73,7 +74,7 @@ struct svc_cred {
 static int
 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
                gss_OID mech, gss_buffer_desc *context_token,
-               int32_t endtime)
+               int32_t endtime, char *client_name)
 {
        FILE *f;
        int i;
@@ -98,9 +99,10 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
        qword_printint(f, cred->cr_gid);
        qword_printint(f, cred->cr_ngroups);
        printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), "
-                "uid: %d, gid: %d, num aux grps: %d:\n",
+                "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n",
                 fname, out_handle->length, context_token->length,
                 endtime, endtime - time(0),
+                client_name ? client_name : "<null>",
                 cred->cr_uid, cred->cr_gid, cred->cr_ngroups);
        for (i=0; i < cred->cr_ngroups; i++) {
                qword_printint(f, cred->cr_groups[i]);
@@ -108,6 +110,8 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
        }
        qword_print(f, fname);
        qword_printhex(f, context_token->value, context_token->length);
+       if (client_name)
+               qword_print(f, client_name);
        err = qword_eol(f);
        if (err) {
                printerr(1, "WARNING: error writing to downcall channel "
@@ -307,6 +311,75 @@ print_hexl(const char *description, unsigned char *cp, int length)
 }
 #endif
 
+static int
+get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name)
+{
+       char *p, *sname = NULL;
+       if (strchr(name->value, '@') && strchr(name->value, '/')) {
+               if ((sname = calloc(name->length, 1)) == NULL) {
+                       printerr(0, "ERROR: get_krb5_hostbased_name failed "
+                                "to allocate %d bytes\n", name->length);
+                       return -1;
+               }
+               /* read in name and instance and replace '/' with '@' */
+               sscanf(name->value, "%[^@]", sname);
+               p = strrchr(sname, '/');
+               if (p == NULL) {    /* The '@' preceeded the '/' */
+                       free(sname);
+                       return -1;
+               }
+               *p = '@';
+       }
+       *hostbased_name = sname;
+       return 0;
+}
+
+static int
+get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
+                         char **hostbased_name)
+{
+       u_int32_t       maj_stat, min_stat;
+       gss_buffer_desc name;
+       gss_OID         name_type = GSS_C_NO_OID;
+       char            *cname;
+       int             res = -1;
+
+       *hostbased_name = NULL;     /* preset in case we fail */
+
+       /* Get the client's gss authenticated name */
+       maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
+       if (maj_stat != GSS_S_COMPLETE) {
+               pgsserr("get_hostbased_client_name: gss_display_name",
+                       maj_stat, min_stat, mech);
+               goto out_err;
+       }
+       if (name.length >= 0xffff) {        /* don't overflow */
+               printerr(0, "ERROR: get_hostbased_client_name: "
+                        "received gss_name is too long (%d bytes)\n",
+                        name.length);
+               goto out_rel_buf;
+       }
+
+       /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
+        * an NT_HOSTBASED_SERVICE name */
+       if (g_OID_equal(&krb5oid, mech)) {
+               if (get_krb5_hostbased_name(&name, &cname) == 0)
+                       *hostbased_name = cname;
+       }
+
+       /* No support for SPKM3, just print a warning (for now) */
+       if (g_OID_equal(&spkm3oid, mech)) {
+               printerr(1, "WARNING: get_hostbased_client_name: "
+                        "no hostbased_name support for SPKM3\n");
+       }
+
+       res = 0;
+out_rel_buf:
+       gss_release_buffer(&min_stat, &name);
+out_err:
+       return res;
+}
+
 void
 handle_nullreq(FILE *f) {
        /* XXX initialize to a random integer to reduce chances of unnecessary
@@ -325,7 +398,7 @@ handle_nullreq(FILE *f) {
                                null_token = {.value = NULL};
        u_int32_t               ret_flags;
        gss_ctx_id_t            ctx = GSS_C_NO_CONTEXT;
-       gss_name_t              client_name;
+       gss_name_t              client_name = NULL;
        gss_OID                 mech = GSS_C_NO_OID;
        u_int32_t               maj_stat = GSS_S_FAILURE, min_stat = 0;
        u_int32_t               ignore_min_stat;
@@ -334,6 +407,7 @@ handle_nullreq(FILE *f) {
        static int              lbuflen = 0;
        static char             *cp;
        int32_t                 ctx_endtime;
+       char                    *hostbased_name = NULL;
 
        printerr(1, "handling null request\n");
 
@@ -396,11 +470,13 @@ handle_nullreq(FILE *f) {
        if (get_ids(client_name, mech, &cred)) {
                /* get_ids() prints error msg */
                maj_stat = GSS_S_BAD_NAME; /* XXX ? */
-               gss_release_name(&ignore_min_stat, &client_name);
                goto out_err;
        }
-       gss_release_name(&ignore_min_stat, &client_name);
-
+       if (get_hostbased_client_name(client_name, mech, &hostbased_name)) {
+               /* get_hostbased_client_name() prints error msg */
+               maj_stat = GSS_S_BAD_NAME; /* XXX ? */
+               goto out_err;
+       }
 
        /* Context complete. Pass handle_seq in out_handle to use
         * for context lookup in the kernel. */
@@ -419,7 +495,8 @@ handle_nullreq(FILE *f) {
        /* We no longer need the gss context */
        gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
 
-       do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime);
+       do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
+                       hostbased_name);
 continue_needed:
        send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
                        &out_handle, &out_tok);
@@ -428,6 +505,9 @@ out:
                free(ctx_token.value);
        if (out_tok.value != NULL)
                gss_release_buffer(&ignore_min_stat, &out_tok);
+       if (client_name)
+               gss_release_name(&ignore_min_stat, &client_name);
+       free(hostbased_name);
        printerr(1, "finished handling null request\n");
        return;
 
index 4dabb3d5b989a6861a1265c98eba19721aa5dc53..421804883383736dcfb5c3e5986193df2d779ecd 100644 (file)
@@ -1,6 +1,5 @@
 ## Process this file with automake to produce Makefile.in
 
-man5_MANS      = idmapd.conf.man
 man8_MANS      = idmapd.man
 
 RPCPREFIX      = rpc.
@@ -8,7 +7,6 @@ KPREFIX         = @kprefix@
 sbin_PROGRAMS  = idmapd
 
 EXTRA_DIST = \
-       $(man5_MANS) \
        $(man8_MANS) \
        idmapd.conf
 
@@ -48,8 +46,8 @@ uninstall-hook:
 
 # XXX This makes some assumptions about what automake does.
 # XXX But there is no install-man-hook or install-man-local.
-install-man: install-man5 install-man8 install-man-links
-uninstall-man: uninstall-man5 uninstall-man8 uninstall-man-links
+install-man: install-man8 install-man-links
+uninstall-man: uninstall-man8 uninstall-man-links
 
 install-man-links:
        (cd $(DESTDIR)$(man8dir) && \
index e47f0a22e938d128ae982ffbba2d487367961b4a..3d2ffff70e3a0e923edce875447545b6ea0646d1 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -56,8 +57,7 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/support/include/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
-       "$(DESTDIR)$(man8dir)"
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"
 PROGRAMS = $(sbin_PROGRAMS)
 am_idmapd_OBJECTS = atomicio.$(OBJEXT) idmapd.$(OBJEXT) \
        strlcat.$(OBJEXT) strlcpy.$(OBJEXT)
@@ -99,10 +99,9 @@ am__nobase_list = $(am__nobase_strip_setup); \
 am__base_list = \
   sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
   sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-man5dir = $(mandir)/man5
 man8dir = $(mandir)/man8
 NROFF = nroff
-MANS = $(man5_MANS) $(man8_MANS)
+MANS = $(man8_MANS)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -163,6 +162,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -229,6 +229,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -264,12 +265,10 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-man5_MANS = idmapd.conf.man
 man8_MANS = idmapd.man
 RPCPREFIX = rpc.
 KPREFIX = @kprefix@
 EXTRA_DIST = \
-       $(man5_MANS) \
        $(man8_MANS) \
        idmapd.conf
 
@@ -403,40 +402,6 @@ mostlyclean-libtool:
 
 clean-libtool:
        -rm -rf .libs _libs
-install-man5: $(man5_MANS)
-       @$(NORMAL_INSTALL)
-       test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
-       @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \
-       { for i in $$list; do echo "$$i"; done; \
-       } | while read p; do \
-         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; echo "$$p"; \
-       done | \
-       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
-             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
-       sed 'N;N;s,\n, ,g' | { \
-       list=; while read file base inst; do \
-         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
-           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
-           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
-         fi; \
-       done; \
-       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
-       while read files; do \
-         test -z "$$files" || { \
-           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
-           $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
-       done; }
-
-uninstall-man5:
-       @$(NORMAL_UNINSTALL)
-       @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \
-       files=`{ for i in $$list; do echo "$$i"; done; \
-       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
-             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
-       test -z "$$files" || { \
-         echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \
-         cd "$(DESTDIR)$(man5dir)" && rm -f $$files; }
 install-man8: $(man8_MANS)
        @$(NORMAL_INSTALL)
        test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
@@ -571,7 +536,7 @@ check-am: all-am
 check: check-am
 all-am: Makefile $(PROGRAMS) $(MANS)
 installdirs:
-       for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \
+       for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \
          test -z "$$dir" || $(MKDIR_P) "$$dir"; \
        done
 install: install-am
@@ -680,14 +645,13 @@ uninstall-am: uninstall-man uninstall-sbinPROGRAMS
        install install-am install-data install-data-am install-dvi \
        install-dvi-am install-exec install-exec-am install-exec-hook \
        install-html install-html-am install-info install-info-am \
-       install-man install-man5 install-man8 install-pdf \
-       install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
-       install-strip installcheck installcheck-am installdirs \
-       maintainer-clean maintainer-clean-generic mostlyclean \
-       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-       pdf pdf-am ps ps-am tags uninstall uninstall-am uninstall-hook \
-       uninstall-man uninstall-man5 uninstall-man8 \
-       uninstall-sbinPROGRAMS
+       install-man install-man8 install-pdf install-pdf-am install-ps \
+       install-ps-am install-sbinPROGRAMS install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am uninstall-hook uninstall-man \
+       uninstall-man8 uninstall-sbinPROGRAMS
 
 
 #######################################################################
@@ -711,8 +675,8 @@ uninstall-hook:
 
 # XXX This makes some assumptions about what automake does.
 # XXX But there is no install-man-hook or install-man-local.
-install-man: install-man5 install-man8 install-man-links
-uninstall-man: uninstall-man5 uninstall-man8 uninstall-man-links
+install-man: install-man8 install-man-links
+uninstall-man: uninstall-man8 uninstall-man-links
 
 install-man-links:
        (cd $(DESTDIR)$(man8dir) && \
diff --git a/utils/idmapd/idmapd.conf.man b/utils/idmapd/idmapd.conf.man
deleted file mode 100644 (file)
index 02722b1..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-.\"    $OpenBSD: mdoc.template,v 1.6 2001/02/03 08:22:44 niklas Exp $
-.\"
-.\" The following requests are required for all man pages.
-.Dd July 16, 2003
-.Dt idmapd.conf 5
-.Os
-.Sh NAME
-.Nm idmapd.conf
-.Nd configuration file for idmapd, the NFSv4 ID <-> Name Mapper
-.Sh SYNOPSIS
-Configuration file for idmapd, the NFSv4 ID <-> Name Mapper
-.Sh DESCRIPTION
-The
-.Nm
-configuration file has two sections, initiated by the strings
-[General] and [Mapping].  Each section may contain lines of the form
-.Dl ""
-.Dl variable = value
-.Dl ""
-The variables allowed in the General section are
-.Va Verbosity,
-.Va Pipefs-Directory,
-and
-.Va Domain,
-whose values have the same effect as the arguments to the
-.Fl v,
-.Fl p,
-and
-.Fl d
-commandline options, respectively.  The variables allowed in the
-Mapping section are
-.Va Nobody-User
-and
-.Va Nobody-Group,
-which have the same effect as the
-.Fl U
-and
-.Fl G
-commandline options.
-'
-.Sh EXAMPLES
-'
-An example
-.Pa /etc/idmapd.conf
-file:
-'
-.Bd -literal
-[General]
-
-Verbosity = 0
-Pipefs-Directory = /var/lib/nfs/rpc_pipefs
-Domain = localdomain
-
-[Mapping]
-
-Nobody-User = nobody
-Nobody-Group = nobody
-.Ed
-'
-.Sh SEE ALSO
-.Xr idmapd 8
-.\".Sh SEE ALSO
-.\".Xr nylon.conf 4
-.\" .Sh COMPATIBILITY
-.\".Sh STANDARDS
-.\".Sh ACKNOWLEDGEMENTS
-.Sh AUTHORS
-The idmapd software has been developed by Marius Aamodt Eriksen
-.Aq marius@citi.umich.edu .
-.\" .Sh HISTORY
-.\".Sh BUGS
-.\"Please report any bugs to Marius Aamodt Eriksen
-.\".Aq marius@monkey.org .
-.\" .Sh CAVEATS
index e5a366e04d588a5bd49ac236b58398379d53936f..d24c26f3bfa8d38ffaee87db878343a56f4236d4 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -45,6 +45,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -176,6 +177,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -242,6 +244,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 28b722c7e101034fe9fde2a7039b221c69dd29eb..5cff00928b637a37e3c71a32b9e60d3b59594e9e 100644 (file)
@@ -194,18 +194,36 @@ void free_all(void)
 static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
 int inline check_vers(char *mopt, char *field)
 {
-       int i;
+       int i, found=0;
 
-       if (strncmp("mountvers", field, strlen("mountvers")) != 0) {
-               for (i=0; versions[i]; i++) 
-                       if (strcasestr(mopt, versions[i]) != NULL)
-                               return 1;
+       /*
+        * First check to see if the config setting is one 
+        * of the many version settings
+        */
+       for (i=0; versions[i]; i++) { 
+               if (strcasestr(field, versions[i]) != NULL) {
+                       found++;
+                       break;
+               }
+       }
+       if (!found)
+               return 0;
+       /*
+        * It appears the version is being set, now see
+        * if the version appears on the command 
+        */
+       for (i=0; versions[i]; i++)  {
+               if (strcasestr(mopt, versions[i]) != NULL)
+                       return 1;
        }
+
        return 0;
 }
 
 unsigned long config_default_vers;
 unsigned long config_default_proto;
+extern sa_family_t config_default_family;
+
 /*
  * Check to see if a default value is being set.
  * If so, set the appropriate global value which will 
@@ -227,6 +245,10 @@ int inline default_value(char *mopt)
                                xlog_warn("Unable to set default protocol : %s", 
                                        strerror(errno));
                        }
+                       if (!nfs_nfs_proto_family(options, &config_default_family)) {
+                               xlog_warn("Unable to set default family : %s", 
+                                       strerror(errno));
+                       }
                } else {
                        xlog_warn("Unable to alloc memory for default protocol");
                }
index 355df796c2448c05fb25cab6f620491de8ec2cea..82b9169a10462dad5f1efbdb55596878f17db10f 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -593,6 +594,9 @@ int main(int argc, char *argv[])
        if (mnt_err == EX_BG) {
                printf(_("%s: backgrounding \"%s\"\n"),
                        progname, spec);
+               printf(_("%s: mount options: \"%s\"\n"),
+                       progname, extra_opts);
+
                fflush(stdout);
 
                /*
index 7b1152a4b3fa479e121a8709af7a42dd40081c48..8dc183a16e78983ef8fcf8f79506275b1c635763 100644 (file)
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
 #include <rpc/pmap_clnt.h>
 
+#include "sockaddr.h"
 #include "xcommon.h"
 #include "mount.h"
 #include "nls.h"
 #define CONNECT_TIMEOUT        (20)
 #define MOUNT_TIMEOUT  (30)
 
-#if SIZEOF_SOCKLEN_T - 0 == 0
-#define socklen_t unsigned int
-#endif
-
 extern int nfs_mount_data_version;
 extern char *progname;
 extern int verbose;
@@ -193,8 +191,18 @@ static const unsigned int *nfs_default_proto()
 }
 #endif /* MOUNT_CONFIG */
 
-static int nfs_lookup(const char *hostname, const sa_family_t family,
-                     struct sockaddr *sap, socklen_t *salen)
+/**
+ * nfs_lookup - resolve hostname to an IPv4 or IPv6 socket address
+ * @hostname: pointer to C string containing DNS hostname to resolve
+ * @family: address family hint
+ * @sap: pointer to buffer to fill with socket address
+ * @len: IN: size of buffer to fill; OUT: size of socket address
+ *
+ * Returns 1 and places a socket address at @sap if successful;
+ * otherwise zero.
+ */
+int nfs_lookup(const char *hostname, const sa_family_t family,
+               struct sockaddr *sap, socklen_t *salen)
 {
        struct addrinfo *gai_results;
        struct addrinfo gai_hint = {
@@ -242,25 +250,6 @@ static int nfs_lookup(const char *hostname, const sa_family_t family,
        return ret;
 }
 
-/**
- * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
- * @hostname: pointer to C string containing DNS hostname to resolve
- * @sap: pointer to buffer to fill with socket address
- * @len: IN: size of buffer to fill; OUT: size of socket address
- *
- * Returns 1 and places a socket address at @sap if successful;
- * otherwise zero.
- */
-int nfs_name_to_address(const char *hostname,
-                       struct sockaddr *sap, socklen_t *salen)
-{
-#ifdef IPV6_SUPPORTED
-       return nfs_lookup(hostname, AF_UNSPEC, sap, salen);
-#else  /* !IPV6_SUPPORTED */
-       return nfs_lookup(hostname, AF_INET, sap, salen);
-#endif /* !IPV6_SUPPORTED */
-}
-
 /**
  * nfs_gethostbyname - resolve a hostname to an IPv4 address
  * @hostname: pointer to a C string containing a DNS hostname
@@ -283,8 +272,8 @@ int nfs_gethostbyname(const char *hostname, struct sockaddr_in *sin)
  *             OUT: length of converted socket address
  *
  * Convert a presentation format address string to a socket address.
- * Similar to nfs_name_to_address(), but the DNS query is squelched,
- * and won't make any noise if the getaddrinfo() call fails.
+ * Similar to nfs_lookup(), but the DNS query is squelched, and it
+ * won't make any noise if the getaddrinfo() call fails.
  *
  * Returns 1 and fills in @sap and @salen if successful; otherwise zero.
  *
@@ -549,8 +538,8 @@ static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen,
                          struct pmap *pmap, const unsigned long *versions,
                          const unsigned int *protos)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *saddr = (struct sockaddr *)&address;
+       union nfs_sockaddr address;
+       struct sockaddr *saddr = &address.sa;
        const unsigned long prog = pmap->pm_prog, *p_vers;
        const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
        const u_short port = (u_short) pmap->pm_port;
@@ -840,8 +829,8 @@ int start_statd(void)
 int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
                      const struct pmap *pmap, const dirpath *argp)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *saddr = (struct sockaddr *)&address;
+       union nfs_sockaddr address;
+       struct sockaddr *saddr = &address.sa;
        struct pmap mnt_pmap = *pmap;
        struct timeval timeout = {
                .tv_sec         = MOUNT_TIMEOUT >> 3,
@@ -1284,11 +1273,13 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
 
 /*
  * Returns TRUE if @protocol contains a valid value for this option,
- * or FALSE if the option was specified with an invalid value.
+ * or FALSE if the option was specified with an invalid value. On
+ * error, errno is set.
  */
 int
 nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol)
 {
+       sa_family_t family;
        char *option;
 
        switch (po_rightmost(options, nfs_transport_opttbl)) {
@@ -1300,16 +1291,12 @@ nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol)
                return 1;
        case 2: /* proto */
                option = po_get(options, "proto");
-               if (option) {
-                       if (strcmp(option, "tcp") == 0) {
-                               *protocol = IPPROTO_TCP;
-                               return 1;
-                       }
-                       if (strcmp(option, "udp") == 0) {
-                               *protocol = IPPROTO_UDP;
-                               return 1;
+               if (option != NULL) {
+                       if (!nfs_get_proto(option, &family, protocol)) {
+                               errno = EPROTONOSUPPORT;
+                               return 0;
                        }
-                       return 0;
+                       return 1;
                }
        }
 
@@ -1351,6 +1338,61 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port)
        return 1;
 }
 
+#ifdef IPV6_SUPPORTED
+sa_family_t    config_default_family = AF_UNSPEC;
+
+static int
+nfs_verify_family(sa_family_t family)
+{
+       return 1;
+}
+#else /* IPV6_SUPPORTED */
+sa_family_t    config_default_family = AF_INET;
+
+static int
+nfs_verify_family(sa_family_t family)
+{
+       if (family != AF_INET)
+               return 0;
+
+       return 1;
+}
+#endif /* IPV6_SUPPORTED */
+
+/*
+ * Returns TRUE and fills in @family if a valid NFS protocol option
+ * is found, or FALSE if the option was specified with an invalid value
+ * or if the protocol family isn't supported. On error, errno is set.
+ */
+int nfs_nfs_proto_family(struct mount_options *options,
+                               sa_family_t *family)
+{
+       unsigned long protocol;
+       char *option;
+       sa_family_t tmp_family = config_default_family;
+
+       switch (po_rightmost(options, nfs_transport_opttbl)) {
+       case 0: /* udp */
+       case 1: /* tcp */
+               /* for compatibility; these are always AF_INET */
+               *family = AF_INET;
+               return 1;
+       case 2: /* proto */
+               option = po_get(options, "proto");
+               if (option != NULL &&
+                   !nfs_get_proto(option, &tmp_family, &protocol))
+                       goto out_err;
+       }
+
+       if (!nfs_verify_family(tmp_family))
+               goto out_err;
+       *family = tmp_family;
+       return 1;
+out_err:
+       errno = EAFNOSUPPORT;
+       return 0;
+}
+
 /*
  * "mountprog" is supported only by the legacy mount command.  The
  * kernel mount client does not support this option.
@@ -1414,24 +1456,22 @@ nfs_mount_version(struct mount_options *options, unsigned long *version)
 
 /*
  * Returns TRUE if @protocol contains a valid value for this option,
- * or FALSE if the option was specified with an invalid value.
+ * or FALSE if the option was specified with an invalid value. On
+ * error, errno is set.
  */
 static int
 nfs_mount_protocol(struct mount_options *options, unsigned long *protocol)
 {
+       sa_family_t family;
        char *option;
 
        option = po_get(options, "mountproto");
-       if (option) {
-               if (strcmp(option, "tcp") == 0) {
-                       *protocol = IPPROTO_TCP;
-                       return 1;
-               }
-               if (strcmp(option, "udp") == 0) {
-                       *protocol = IPPROTO_UDP;
-                       return 1;
+       if (option != NULL) {
+               if (!nfs_get_proto(option, &family, protocol)) {
+                       errno = EPROTONOSUPPORT;
+                       return 0;
                }
-               return 0;
+               return 1;
        }
 
        /*
@@ -1472,6 +1512,40 @@ nfs_mount_port(struct mount_options *options, unsigned long *port)
        return 1;
 }
 
+/*
+ * Returns TRUE and fills in @family if a valid MNT protocol option
+ * is found, or FALSE if the option was specified with an invalid value
+ * or if the protocol family isn't supported. On error, errno is set.
+ */
+int nfs_mount_proto_family(struct mount_options *options,
+                               sa_family_t *family)
+{
+       unsigned long protocol;
+       char *option;
+       sa_family_t tmp_family = config_default_family;
+
+       option = po_get(options, "mountproto");
+       if (option != NULL) {
+               if (!nfs_get_proto(option, &tmp_family, &protocol))
+                       goto out_err;
+               if (!nfs_verify_family(tmp_family))
+                       goto out_err;
+               *family = tmp_family;
+               return 1;
+       }
+
+       /*
+        * MNT transport protocol wasn't specified.  If the NFS
+        * transport protocol was specified, derive the family
+        * from that; otherwise, return the default family for
+        * NFS.
+        */
+       return nfs_nfs_proto_family(options, family);
+out_err:
+       errno = EAFNOSUPPORT;
+       return 0;
+}
+
 /**
  * nfs_options2pmap - set up pmap structs based on mount options
  * @options: pointer to mount options
index 7eb89b049360d7898827294c41a467915e7b3b3e..2a3a1105498df483adbd5722ae226e32763fb1dd 100644 (file)
@@ -44,7 +44,8 @@ int nfs_probe_bothports(const struct sockaddr *, const socklen_t,
                        struct pmap *, const struct sockaddr *,
                        const socklen_t, struct pmap *);
 int nfs_gethostbyname(const char *, struct sockaddr_in *);
-int nfs_name_to_address(const char *, struct sockaddr *, socklen_t *);
+int nfs_lookup(const char *hostname, const sa_family_t family,
+               struct sockaddr *sap, socklen_t *salen);
 int nfs_string_to_sockaddr(const char *, struct sockaddr *, socklen_t *);
 int nfs_present_sockaddr(const struct sockaddr *,
                         const socklen_t, char *, const size_t);
@@ -56,6 +57,8 @@ int clnt_ping(struct sockaddr_in *, const unsigned long,
 
 struct mount_options;
 
+int nfs_nfs_proto_family(struct mount_options *options, sa_family_t *family);
+int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family);
 int nfs_nfs_version(struct mount_options *options, unsigned long *version);
 int  nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol);
 
index 22996375813531a4ff2b60c882c0521d42447764..c64de5fa2d875d4904bf26db1f1378eff27b4314 100644 (file)
@@ -58,9 +58,17 @@ The server's hostname and export pathname
 are separated by a colon, while
 the mount options are separated by commas. The remaining fields
 are separated by blanks or tabs.
+.P
 The server's hostname can be an unqualified hostname,
 a fully qualified domain name,
-or a dotted quad IPv4 address.
+a dotted quad IPv4 address, or
+an IPv6 address enclosed in square brackets.
+Link-local and site-local IPv6 addresses must be accompanied by an
+interface identifier.
+See
+.BR ipv6 (7)
+for details on specifying raw IPv6 addresses.
+.P
 The
 .I fstype
 field contains either "nfs" (for version 2 or version 3 NFS mounts)
@@ -355,7 +363,11 @@ The number of minutes that the
 command retries an NFS mount operation
 in the foreground or background before giving up.
 If this option is not specified, the default value for foreground mounts
-is 2 minutes, and the default value for background mounts is 10000 minutes (80 minutes shy of one week).
+is 2 minutes, and the default value for background mounts is 10000 minutes
+(80 minutes shy of one week).
+If a value of zero is specified, the
+.BR mount (8)
+command exits immediately after the first failure.
 .TP 1.5i
 .BI sec= mode
 The RPCGSS security flavor to use for accessing files on this mount point.
@@ -470,32 +482,38 @@ for mounting the
 .B nfs
 file system type.
 .TP 1.5i
-.BI proto= transport
-The transport the NFS client uses
+.BI proto= netid
+The transport protocol name and protocol family the NFS client uses
 to transmit requests to the NFS server for this mount point.
-.I transport
-can be either
-.B udp
-or
-.BR tcp .
-Each transport uses different default
+If an NFS server has both an IPv4 and an IPv6 address, using a specific
+netid will force the use of IPv4 or IPv6 networking to communicate
+with that server.
+.IP
+If support for TI-RPC is built into the
+.B mount.nfs
+command,
+.I netid
+is a valid netid listed in
+.IR /etc/netconfig .
+Otherwise,
+.I netid
+is one of "tcp," "udp," or "rdma," and only IPv4 may be used.
+.IP
+Each transport protocol uses different default
 .B retrans
 and
 .B timeo
-settings; refer to the description of these two mount options for details.
+settings.
+Refer to the description of these two mount options for details.
 .IP
 In addition to controlling how the NFS client transmits requests to
 the server, this mount option also controls how the
 .BR mount (8)
 command communicates with the server's rpcbind and mountd services.
-Specifying
-.B proto=tcp
-forces all traffic from the
+Specifying a netid that uses TCP forces all traffic from the
 .BR mount (8)
 command and the NFS client to use TCP.
-Specifying
-.B proto=udp
-forces all traffic types to use UDP.
+Specifying a netid that uses UDP forces all traffic types to use UDP.
 .IP
 If the
 .B proto
@@ -548,15 +566,20 @@ or the server's mountd service is not available on the advertised port.
 This option can be used when mounting an NFS server
 through a firewall that blocks the rpcbind protocol.
 .TP 1.5i
-.BI mountproto= transport
-The transport the NFS client uses
+.BI mountproto= netid
+The transport protocol name and protocol family the NFS client uses
 to transmit requests to the NFS server's mountd service when performing
 this mount request, and when later unmounting this mount point.
-.I transport
-can be either
-.B udp
-or
-.BR tcp .
+.IP
+If support for TI-RPC is built into the
+.B mount.nfs
+command,
+.I netid
+is a valid netid listed in
+.IR /etc/netconfig .
+Otherwise,
+.I netid
+is one of "tcp" or "udp," and only IPv4 may be used.
 .IP
 This option can be used when mounting an NFS server
 through a firewall that blocks a particular transport.
@@ -566,6 +589,7 @@ option, different transports for mountd requests and NFS requests
 can be specified.
 If the server's mountd service is not available via the specified
 transport, the mount request fails.
+.IP
 Refer to the TRANSPORT METHODS section for more on how the
 .B mountproto
 mount option interacts with the
@@ -709,17 +733,26 @@ for mounting the
 .B nfs4
 file system type.
 .TP 1.5i
-.BI proto= transport
-The transport the NFS client uses
+.BI proto= netid
+The transport protocol name and protocol family the NFS client uses
 to transmit requests to the NFS server for this mount point.
-.I transport
-can be either
-.B udp
-or
-.BR tcp .
+If an NFS server has both an IPv4 and an IPv6 address, using a specific
+netid will force the use of IPv4 or IPv6 networking to communicate
+with that server.
+.IP
+If support for TI-RPC is built into the
+.B mount.nfs
+command,
+.I netid
+is a valid netid listed in
+.IR /etc/netconfig .
+Otherwise,
+.I netid
+is one of "tcp" or "udp," and only IPv4 may be used.
+.IP
 All NFS version 4 servers are required to support TCP,
 so if this mount option is not specified, the NFS version 4 client
-uses the TCP transport protocol.
+uses the TCP protocol.
 Refer to the TRANSPORT METHODS section for more details.
 .TP 1.5i
 .BI port= n
@@ -779,7 +812,8 @@ The DATA AND METADATA COHERENCE section discusses
 the behavior of this option in more detail.
 .TP 1.5i
 .BI clientaddr= n.n.n.n
-Specifies  a  single  IPv4  address  (in dotted-quad form)
+Specifies a single IPv4 address (in dotted-quad form),
+or a non-link-local IPv6 address,
 that the NFS client advertises to allow servers
 to perform NFS version 4 callback requests against
 files on this mount point. If  the  server is unable to
@@ -855,6 +889,14 @@ This example can be used to mount /usr over NFS.
 .TA 2.5i +0.7i +0.7i +.7i
        server:/export  /usr    nfs     ro,nolock,nocto,actimeo=3600    0 0
 .FI
+.P
+This example shows how to mount an NFS server
+using a raw IPv6 link-local address.
+.P
+.NF
+.TA 2.5i +0.7i +0.7i +.7i
+       [fe80::215:c5ff:fb3e:e2b1%eth0]:/export /mnt    nfs     defaults        0 0
+.FI
 .SH "TRANSPORT METHODS"
 NFS clients send requests to NFS servers via
 Remote Procedure Calls, or
@@ -1498,6 +1540,8 @@ such as security negotiation, server referrals, and named attributes.
 .BR mount.nfs (5),
 .BR umount.nfs (5),
 .BR exports (5),
+.BR netconfig (5),
+.BR ipv6 (7),
 .BR nfsd (8),
 .BR sm-notify (8),
 .BR rpc.statd (8),
index a2f318fa47da13b3af4885ee514bd7d6e1fc7703..4a2fab7dfabf326f268b31952275583a23004d05 100644 (file)
@@ -217,8 +217,11 @@ int nfs4mount(const char *spec, const char *node, int flags,
                                progname);
                goto fail;
        }
-       snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
-                old_opts, *old_opts ? "," : "", s);
+       if (running_bg)
+               strncpy(new_opts, old_opts, sizeof(new_opts));
+       else
+               snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
+                        old_opts, *old_opts ? "," : "", s);
        *extra_opts = xstrdup(new_opts);
 
        /* Set default options.
@@ -434,15 +437,17 @@ int nfs4mount(const char *spec, const char *node, int flags,
                        break;
                }
 
-               switch(rpc_createerr.cf_stat){
-               case RPC_TIMEDOUT:
-                       break;
-               case RPC_SYSTEMERROR:
-                       if (errno == ETIMEDOUT)
+               if (!bg) {
+                       switch(rpc_createerr.cf_stat) {
+                       case RPC_TIMEDOUT:
                                break;
-               default:
-                       rpc_mount_errors(hostname, 0, bg);
-                       goto fail;
+                       case RPC_SYSTEMERROR:
+                               if (errno == ETIMEDOUT)
+                                       break;
+                       default:
+                               rpc_mount_errors(hostname, 0, bg);
+                               goto fail;
+                       }
                }
 
                if (bg && !running_bg) {
index 6355681d4b520eeb3bdeacb26ed81cf797ea33cc..6b3356c05efe57d6a7ee0efeac665c530c2446ad 100644 (file)
@@ -170,7 +170,7 @@ parse_options(char *old_opts, struct nfs_mount_data *data,
        struct pmap *mnt_pmap = &mnt_server->pmap;
        struct pmap *nfs_pmap = &nfs_server->pmap;
        int len;
-       char *opt, *opteq, *p, *opt_b;
+       char *opt, *opteq, *p, *opt_b, *tmp_opts;
        char *mounthost = NULL;
        char cbuf[128];
        int open_quote = 0;
@@ -179,7 +179,8 @@ parse_options(char *old_opts, struct nfs_mount_data *data,
        *bg = 0;
 
        len = strlen(new_opts);
-       for (p=old_opts, opt_b=NULL; p && *p; p++) {
+       tmp_opts = xstrdup(old_opts);
+       for (p=tmp_opts, opt_b=NULL; p && *p; p++) {
                if (!opt_b)
                        opt_b = p;              /* begin of the option item */
                if (*p == '"')
@@ -457,10 +458,12 @@ parse_options(char *old_opts, struct nfs_mount_data *data,
                        goto out_bad;
                *mnt_server->hostname = mounthost;
        }
+       free(tmp_opts);
        return 1;
  bad_parameter:
        nfs_error(_("%s: Bad nfs mount parameter: %s\n"), progname, opt);
  out_bad:
+       free(tmp_opts);
        return 0;
 }
 
index c5505b1edf6d436532f93310f0d2a433e70c19a2..9d798a2ff347513779b646b88692ae873844b158 100644 (file)
@@ -169,10 +169,15 @@ out:
 static int nfs_umount_do_umnt(struct mount_options *options,
                              char **hostname, char **dirname)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *sap = (struct sockaddr *)&address;
+       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)) {
                nfs_error(_("%s: bad mount options"), progname);
@@ -189,8 +194,10 @@ static int nfs_umount_do_umnt(struct mount_options *options,
                return EX_FAIL;
        }
 
-       if (nfs_name_to_address(*hostname, sap, &salen) == 0)
-               /* nfs_name_to_address reports any errors */
+       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)
index b5956495eeebf164638d9613102faf81e503a4a5..9b8c38fa9b86bb045be854a63e6b4bff3d13bc84 100644 (file)
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include "sockaddr.h"
 #include "xcommon.h"
 #include "mount.h"
 #include "nls.h"
+#include "nfsrpc.h"
 #include "mount_constants.h"
 #include "stropts.h"
 #include "error.h"
 #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
@@ -81,8 +87,7 @@ struct nfsmount_info {
                                *node,          /* mounted-on dir */
                                *type;          /* "nfs" or "nfs4" */
        char                    *hostname;      /* server's hostname */
-       struct sockaddr_storage address;        /* server's address */
-       socklen_t               salen;          /* size of server's address */
+       struct addrinfo         *address;       /* server's addresses */
 
        struct mount_options    *options;       /* parsed mount options */
        char                    **extra_opts;   /* string for /etc/mtab */
@@ -204,9 +209,9 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap,
                                        socklen_t salen,
                                        struct mount_options *options)
 {
-       struct sockaddr_storage dummy;
-       struct sockaddr *my_addr = (struct sockaddr *)&dummy;
-       socklen_t my_len = sizeof(dummy);
+       union nfs_sockaddr address;
+       struct sockaddr *my_addr = &address.sa;
+       socklen_t my_len = sizeof(address);
 
        if (po_contains(options, "clientaddr") == PO_FOUND)
                return 1;
@@ -218,21 +223,33 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap,
 }
 
 /*
- * Resolve the 'mounthost=' hostname and append a new option using
- * the resulting address.
+ * Determine whether to append a 'mountaddr=' option.  The option is needed if:
+ *
+ *   1. "mounthost=" was specified, or
+ *   2. The address families for proto= and mountproto= are different.
  */
-static int nfs_fix_mounthost_option(struct mount_options *options)
+static int nfs_fix_mounthost_option(struct mount_options *options,
+               const char *nfs_hostname)
 {
-       struct sockaddr_storage dummy;
-       struct sockaddr *sap = (struct sockaddr *)&dummy;
-       socklen_t salen = sizeof(dummy);
+       union nfs_sockaddr address;
+       struct sockaddr *sap = &address.sa;
+       socklen_t salen = sizeof(address);
+       sa_family_t nfs_family, mnt_family;
        char *mounthost;
 
+       if (!nfs_nfs_proto_family(options, &nfs_family))
+               return 0;
+       if (!nfs_mount_proto_family(options, &mnt_family))
+               return 0;
+
        mounthost = po_get(options, "mounthost");
-       if (!mounthost)
-               return 1;
+       if (mounthost == NULL) {
+               if (nfs_family == mnt_family)
+                       return 1;
+               mounthost = (char *)nfs_hostname;
+       }
 
-       if (!nfs_name_to_address(mounthost, sap, &salen)) {
+       if (!nfs_lookup(mounthost, mnt_family, sap, &salen)) {
                nfs_error(_("%s: unable to determine mount server's address"),
                                progname);
                return 0;
@@ -319,22 +336,36 @@ static int nfs_set_version(struct nfsmount_info *mi)
  */
 static int nfs_validate_options(struct nfsmount_info *mi)
 {
-       struct sockaddr *sap = (struct sockaddr *)&mi->address;
+       struct addrinfo hint = {
+               .ai_protocol    = (int)IPPROTO_UDP,
+               .ai_flags       = AI_ADDRCONFIG,
+       };
+       sa_family_t family;
+       int error;
 
        if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL))
                return 0;
 
-       mi->salen = sizeof(mi->address);
-       if (!nfs_name_to_address(mi->hostname, sap, &mi->salen))
+       if (!nfs_nfs_proto_family(mi->options, &family))
                return 0;
 
+       hint.ai_family = (int)family;
+       error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address);
+       if (error != 0) {
+               nfs_error(_("%s: Failed to resolve server %s: %s"),
+                       progname, mi->hostname, gai_strerror(error));
+               mi->address = NULL;
+               return 0;
+       }
+
        if (!nfs_set_version(mi))
                return 0;
 
        if (!nfs_append_sloppy_option(mi->options))
                return 0;
 
-       if (!nfs_append_addr_option(sap, mi->salen, mi->options))
+       if (!nfs_append_addr_option(mi->address->ai_addr,
+                                       mi->address->ai_addrlen, mi->options))
                return 0;
 
        return 1;
@@ -371,10 +402,13 @@ static int nfs_extract_server_addresses(struct mount_options *options,
 }
 
 static int nfs_construct_new_options(struct mount_options *options,
+                                    struct sockaddr *nfs_saddr,
                                     struct pmap *nfs_pmap,
+                                    struct sockaddr *mnt_saddr,
                                     struct pmap *mnt_pmap)
 {
        char new_option[64];
+       char *netid;
 
        po_remove_all(options, "nfsprog");
        po_remove_all(options, "mountprog");
@@ -391,20 +425,14 @@ static int nfs_construct_new_options(struct mount_options *options,
        po_remove_all(options, "proto");
        po_remove_all(options, "udp");
        po_remove_all(options, "tcp");
-       switch (nfs_pmap->pm_prot) {
-       case IPPROTO_TCP:
-               snprintf(new_option, sizeof(new_option) - 1,
-                        "proto=tcp");
-               if (po_append(options, new_option) == PO_FAILED)
-                       return 0;
-               break;
-       case IPPROTO_UDP:
-               snprintf(new_option, sizeof(new_option) - 1,
-                        "proto=udp");
-               if (po_append(options, new_option) == PO_FAILED)
-                       return 0;
-               break;
-       }
+       netid = nfs_get_netid(nfs_saddr->sa_family, nfs_pmap->pm_prot);
+       if (netid == NULL)
+               return 0;
+       snprintf(new_option, sizeof(new_option) - 1,
+                        "proto=%s", netid);
+       free(netid);
+       if (po_append(options, new_option) == PO_FAILED)
+               return 0;
 
        po_remove_all(options, "port");
        if (nfs_pmap->pm_port != NFS_PORT) {
@@ -421,20 +449,14 @@ static int nfs_construct_new_options(struct mount_options *options,
                return 0;
 
        po_remove_all(options, "mountproto");
-       switch (mnt_pmap->pm_prot) {
-       case IPPROTO_TCP:
-               snprintf(new_option, sizeof(new_option) - 1,
-                        "mountproto=tcp");
-               if (po_append(options, new_option) == PO_FAILED)
-                       return 0;
-               break;
-       case IPPROTO_UDP:
-               snprintf(new_option, sizeof(new_option) - 1,
-                        "mountproto=udp");
-               if (po_append(options, new_option) == PO_FAILED)
-                       return 0;
-               break;
-       }
+       netid = nfs_get_netid(mnt_saddr->sa_family, mnt_pmap->pm_prot);
+       if (netid == NULL)
+               return 0;
+       snprintf(new_option, sizeof(new_option) - 1,
+                        "mountproto=%s", netid);
+       free(netid);
+       if (po_append(options, new_option) == PO_FAILED)
+               return 0;
 
        po_remove_all(options, "mountport");
        snprintf(new_option, sizeof(new_option) - 1,
@@ -461,12 +483,12 @@ static int nfs_construct_new_options(struct mount_options *options,
 static int
 nfs_rewrite_pmap_mount_options(struct mount_options *options)
 {
-       struct sockaddr_storage nfs_address;
-       struct sockaddr *nfs_saddr = (struct sockaddr *)&nfs_address;
+       union nfs_sockaddr nfs_address;
+       struct sockaddr *nfs_saddr = &nfs_address.sa;
        socklen_t nfs_salen = sizeof(nfs_address);
        struct pmap nfs_pmap;
-       struct sockaddr_storage mnt_address;
-       struct sockaddr *mnt_saddr = (struct sockaddr *)&mnt_address;
+       union nfs_sockaddr mnt_address;
+       struct sockaddr *mnt_saddr = &mnt_address.sa;
        socklen_t mnt_salen = sizeof(mnt_address);
        struct pmap mnt_pmap;
        char *option;
@@ -507,10 +529,15 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
        if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap,
                                 nfs_saddr, nfs_salen, &nfs_pmap)) {
                errno = ESPIPE;
+               if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
+                       errno = EOPNOTSUPP;
+               else if (rpc_createerr.cf_error.re_errno != 0)
+                       errno = rpc_createerr.cf_error.re_errno;
                return 0;
        }
 
-       if (!nfs_construct_new_options(options, &nfs_pmap, &mnt_pmap)) {
+       if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
+                                       mnt_saddr, &mnt_pmap)) {
                errno = EINVAL;
                return 0;
        }
@@ -536,10 +563,6 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
                return 0;
        }
 
-       if (verbose)
-               printf(_("%s: trying text-based options '%s'\n"),
-                       progname, options);
-
        if (mi->fake)
                return 1;
 
@@ -553,10 +576,8 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
        return !result;
 }
 
-/*
- * For "-t nfs vers=2" or "-t nfs vers=3" mounts.
- */
-static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
+static int nfs_do_mount_v3v2(struct nfsmount_info *mi,
+               struct sockaddr *sap, socklen_t salen)
 {
        struct mount_options *options = po_dup(mi->options);
        int result = 0;
@@ -566,7 +587,12 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
                return result;
        }
 
-       if (!nfs_fix_mounthost_option(options)) {
+       if (!nfs_append_addr_option(sap, salen, options)) {
+               errno = EINVAL;
+               goto out_fail;
+       }
+
+       if (!nfs_fix_mounthost_option(options, mi->hostname)) {
                errno = EINVAL;
                goto out_fail;
        }
@@ -586,6 +612,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
                goto out_fail;
        }
 
+       if (verbose)
+               printf(_("%s: trying text-based options '%s'\n"),
+                       progname, *mi->extra_opts);
+
        if (!nfs_rewrite_pmap_mount_options(options))
                goto out_fail;
 
@@ -597,11 +627,36 @@ out_fail:
 }
 
 /*
- * For "-t nfs -o vers=4" or "-t nfs4" mounts.
+ * Attempt a "-t nfs vers=2" or "-t nfs vers=3" mount.
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ * "errno" is set to reflect the individual error.
  */
-static int nfs_try_mount_v4(struct nfsmount_info *mi)
+static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
+{
+       struct addrinfo *ai;
+       int ret;
+
+       for (ai = mi->address; ai != NULL; ai = ai->ai_next) {
+               ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen);
+               if (ret != 0)
+                       return ret;
+
+               switch (errno) {
+               case ECONNREFUSED:
+               case EOPNOTSUPP:
+               case EHOSTUNREACH:
+                       continue;
+               default:
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int nfs_do_mount_v4(struct nfsmount_info *mi,
+               struct sockaddr *sap, socklen_t salen)
 {
-       struct sockaddr *sap = (struct sockaddr *)&mi->address;
        struct mount_options *options = po_dup(mi->options);
        int result = 0;
 
@@ -611,13 +666,30 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
        }
 
        if (mi->version == 0) {
+               if (po_contains(options, "mounthost") ||
+                       po_contains(options, "mountaddr") ||
+                       po_contains(options, "mountvers") ||
+                       po_contains(options, "mountproto")) {
+               /*
+                * Since these mountd options are set assume version 3
+                * is wanted so error out with EPROTONOSUPPORT so the
+                * protocol negation starts with v3.
+                */
+                       errno = EPROTONOSUPPORT;
+                       goto out_fail;
+               }
                if (po_append(options, "vers=4") == PO_FAILED) {
                        errno = EINVAL;
                        goto out_fail;
                }
        }
 
-       if (!nfs_append_clientaddr_option(sap, mi->salen, options)) {
+       if (!nfs_append_addr_option(sap, salen, options)) {
+               errno = EINVAL;
+               goto out_fail;
+       }
+
+       if (!nfs_append_clientaddr_option(sap, salen, options)) {
                errno = EINVAL;
                goto out_fail;
        }
@@ -630,6 +702,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
                goto out_fail;
        }
 
+       if (verbose)
+               printf(_("%s: trying text-based options '%s'\n"),
+                       progname, *mi->extra_opts);
+
        result = nfs_sys_mount(mi, options);
 
 out_fail:
@@ -637,6 +713,33 @@ out_fail:
        return result;
 }
 
+/*
+ * Attempt a "-t nfs -o vers=4" or "-t nfs4" mount.
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ * "errno" is set to reflect the individual error.
+ */
+static int nfs_try_mount_v4(struct nfsmount_info *mi)
+{
+       struct addrinfo *ai;
+       int ret;
+
+       for (ai = mi->address; ai != NULL; ai = ai->ai_next) {
+               ret = nfs_do_mount_v4(mi, ai->ai_addr, ai->ai_addrlen);
+               if (ret != 0)
+                       return ret;
+
+               switch (errno) {
+               case ECONNREFUSED:
+               case EHOSTUNREACH:
+                       continue;
+               default:
+                       break;
+               }
+       }
+       return ret;
+}
+
 /*
  * This is a single pass through the fg/bg loop.
  *
@@ -656,9 +759,10 @@ static int nfs_try_mount(struct nfsmount_info *mi)
                                /* 
                                 * To deal with legacy Linux servers that don't
                                 * automatically export a pseudo root, retry
-                                * ENOENT errors using version 3
+                                * ENOENT errors using version 3. And for
+                                * Linux servers prior to 2.6.25, retry EPERM
                                 */
-                               if (errno != ENOENT)
+                               if (errno != ENOENT && errno != EPERM)
                                        break;
                        }
                }
@@ -856,6 +960,7 @@ int nfsmount_string(const char *spec, const char *node, const char *type,
        struct nfsmount_info mi = {
                .spec           = spec,
                .node           = node,
+               .address        = NULL,
                .type           = type,
                .extra_opts     = extra_opts,
                .flags          = flags,
@@ -871,6 +976,7 @@ int nfsmount_string(const char *spec, const char *node, const char *type,
        } else
                nfs_error(_("%s: internal option parsing error"), progname);
 
+       freeaddrinfo(mi.address);
        free(mi.hostname);
        return retval;
 }
index 1e76cf810b381ce85df789d9de193387b60a9a7a..eba81fcc82556965e026de7d55cd598728d74698 100644 (file)
@@ -8,7 +8,7 @@ KPREFIX         = @kprefix@
 sbin_PROGRAMS  = mountd
 
 mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
-                svc_run.c fsloc.c mountd.h
+                svc_run.c fsloc.c v4root.c mountd.h
 mountd_LDADD = ../../support/export/libexport.a \
               ../../support/nfs/libnfs.a \
               ../../support/misc/libmisc.a \
index bab01c7e4b78ee102ee69adc0fd8bdfe2a6df880..34a6dca7fa56add87688977062f9470a29a287b9 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -61,7 +62,8 @@ PROGRAMS = $(sbin_PROGRAMS)
 am_mountd_OBJECTS = mountd-mountd.$(OBJEXT) \
        mountd-mount_dispatch.$(OBJEXT) mountd-auth.$(OBJEXT) \
        mountd-rmtab.$(OBJEXT) mountd-cache.$(OBJEXT) \
-       mountd-svc_run.$(OBJEXT) mountd-fsloc.$(OBJEXT)
+       mountd-svc_run.$(OBJEXT) mountd-fsloc.$(OBJEXT) \
+       mountd-v4root.$(OBJEXT)
 mountd_OBJECTS = $(am_mountd_OBJECTS)
 am__DEPENDENCIES_1 =
 mountd_DEPENDENCIES = ../../support/export/libexport.a \
@@ -167,6 +169,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -233,6 +236,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -273,7 +277,7 @@ EXTRA_DIST = $(man8_MANS)
 RPCPREFIX = rpc.
 KPREFIX = @kprefix@
 mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
-                svc_run.c fsloc.c mountd.h
+                svc_run.c fsloc.c v4root.c mountd.h
 
 mountd_LDADD = ../../support/export/libexport.a \
               ../../support/nfs/libnfs.a \
@@ -379,6 +383,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mountd-mountd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mountd-rmtab.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mountd-svc_run.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mountd-v4root.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -499,6 +504,20 @@ mountd-fsloc.obj: fsloc.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mountd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mountd-fsloc.obj `if test -f 'fsloc.c'; then $(CYGPATH_W) 'fsloc.c'; else $(CYGPATH_W) '$(srcdir)/fsloc.c'; fi`
 
+mountd-v4root.o: v4root.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mountd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mountd-v4root.o -MD -MP -MF $(DEPDIR)/mountd-v4root.Tpo -c -o mountd-v4root.o `test -f 'v4root.c' || echo '$(srcdir)/'`v4root.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mountd-v4root.Tpo $(DEPDIR)/mountd-v4root.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='v4root.c' object='mountd-v4root.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mountd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mountd-v4root.o `test -f 'v4root.c' || echo '$(srcdir)/'`v4root.c
+
+mountd-v4root.obj: v4root.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mountd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mountd-v4root.obj -MD -MP -MF $(DEPDIR)/mountd-v4root.Tpo -c -o mountd-v4root.obj `if test -f 'v4root.c'; then $(CYGPATH_W) 'v4root.c'; else $(CYGPATH_W) '$(srcdir)/v4root.c'; fi`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mountd-v4root.Tpo $(DEPDIR)/mountd-v4root.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='v4root.c' object='mountd-v4root.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mountd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mountd-v4root.obj `if test -f 'v4root.c'; then $(CYGPATH_W) 'v4root.c'; else $(CYGPATH_W) '$(srcdir)/v4root.c'; fi`
+
 mostlyclean-libtool:
        -rm -f *.lo
 
index 575f207bd028f0d74eed6097a82d485499c4d8b8..13eba70b7bcbab152d2d6a50f4776175c6e48879 100644 (file)
@@ -20,6 +20,7 @@
 #include "exportfs.h"
 #include "mountd.h"
 #include "xmalloc.h"
+#include "v4root.h"
 
 enum auth_error
 {
@@ -102,75 +103,91 @@ auth_reload()
        memset(&my_client, 0, sizeof(my_client));
        xtab_export_read();
        check_useipaddr();
+       v4root_set();
+
        ++counter;
 
        return counter;
 }
 
+static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error)
+{
+       char *n;
+
+       if (use_ipaddr)
+               return strdup(inet_ntoa(caller->sin_addr));
+       n = client_compose(hp);
+       *error = unknown_host;
+       if (!n)
+               return NULL;
+       if (*n)
+               return n;
+       free(n);
+       return strdup("DEFAULT");
+}
+
+/* return static nfs_export with details filled in */
 static nfs_export *
-auth_authenticate_internal(char *what, struct sockaddr_in *caller,
+auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
                           char *path, struct hostent *hp,
                           enum auth_error *error)
 {
-       nfs_export              *exp;
+       nfs_export *exp;
+       int i;
 
-       if (new_cache) {
-               int i;
-               /* return static nfs_export with details filled in */
-               char *n;
-               free(my_client.m_hostname);
-               if (use_ipaddr) {
-                       my_client.m_hostname =
-                               strdup(inet_ntoa(caller->sin_addr));
-               } else {
-                       n = client_compose(hp);
-                       *error = unknown_host;
-                       if (!n)
-                               my_client.m_hostname = NULL;
-                       else if (*n)
-                               my_client.m_hostname = n;
-                       else {
-                               free(n);
-                               my_client.m_hostname = strdup("DEFAULT");
-                       }
+       free(my_client.m_hostname);
+
+       my_client.m_hostname = get_client_hostname(caller, hp, error);
+       if (my_client.m_hostname == NULL)
+               return NULL;
+
+       my_client.m_naddr = 1;
+       my_client.m_addrlist[0] = caller->sin_addr;
+       my_exp.m_client = &my_client;
+
+       exp = NULL;
+       for (i = 0; !exp && i < MCL_MAXTYPES; i++)
+               for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+                       if (strcmp(path, exp->m_export.e_path))
+                               continue;
+                       if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
+                               continue;
+                       if (use_ipaddr && !client_check(exp->m_client, hp))
+                               continue;
+                       break;
                }
-               if (my_client.m_hostname == NULL)
-                       return NULL;
-               my_client.m_naddr = 1;
-               my_client.m_addrlist[0] = caller->sin_addr;
-               my_exp.m_client = &my_client;
-
-               exp = NULL;
-               for (i = 0; !exp && i < MCL_MAXTYPES; i++) 
-                       for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
-                               if (strcmp(path, exp->m_export.e_path))
-                                       continue;
-                               if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
-                                       continue;
-                               if (use_ipaddr && !client_check(exp->m_client, hp))
-                                       continue;
-                               break;
-                       }
-               *error = not_exported;
-               if (!exp)
-                       return exp;
+       *error = not_exported;
+       if (!exp)
+               return NULL;
 
-               my_exp.m_export = exp->m_export;
-               exp = &my_exp;
+       my_exp.m_export = exp->m_export;
+       exp = &my_exp;
+       return exp;
+}
+
+static nfs_export *
+auth_authenticate_internal(char *what, struct sockaddr_in *caller,
+                          char *path, struct hostent *hp,
+                          enum auth_error *error)
+{
+       nfs_export *exp;
 
+       if (new_cache) {
+               exp = auth_authenticate_newcache(what, caller, path, hp, error);
+               if (!exp)
+                       return NULL;
        } else {
                if (!(exp = export_find(hp, path))) {
                        *error = no_entry;
                        return NULL;
                }
-               if (!exp->m_mayexport) {
-                       *error = not_exported;
-                       return NULL;
-               }
+       }
+       if (exp->m_export.e_flags & NFSEXP_V4ROOT) {
+               *error = no_entry;
+               return NULL;
        }
        if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
-                   (ntohs(caller->sin_port) <  IPPORT_RESERVED/2 ||
-                    ntohs(caller->sin_port) >= IPPORT_RESERVED)) {
+                    ntohs(caller->sin_port) >= IPPORT_RESERVED) {
                *error = illegal_port;
                return NULL;
        }
index e4e2f228f848a458a9d6e30a3c6e02ef8b43bec1..d63e10ae1faf431d190e1c1ba5ca2c742eb038a2 100644 (file)
@@ -614,73 +614,54 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
        return qword_eol(f);
 }
 
-void nfsd_export(FILE *f)
+static int is_subdirectory(char *subpath, char *path)
 {
-       /* requests are:
-        *  domain path
-        * determine export options and return:
-        *  domain path expiry flags anonuid anongid fsid
-        */
-
-       char *cp;
-       int i;
-       char *dom, *path;
-       nfs_export *exp, *found = NULL;
-       int found_type = 0;
-       struct in_addr addr;
-       struct hostent *he = NULL;
-
-
-       if (readline(fileno(f), &lbuf, &lbuflen) != 1)
-               return;
+       int l = strlen(path);
 
-       xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf);
+       return strcmp(subpath, path) == 0
+               || (strncmp(subpath, path, l) == 0 && path[l] == '/');
+}
 
-       cp = lbuf;
-       dom = malloc(strlen(cp));
-       path = malloc(strlen(cp));
+static int path_matches(nfs_export *exp, char *path)
+{
+       if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)
+               return is_subdirectory(path, exp->m_export.e_path);
+       return strcmp(path, exp->m_export.e_path) == 0;
+}
 
-       if (!dom || !path)
-               goto out;
+static int client_matches(nfs_export *exp, char *dom, struct hostent *he)
+{
+       if (use_ipaddr)
+               return client_check(exp->m_client, he);
+       return client_member(dom, exp->m_client->m_hostname);
+}
 
-       if (qword_get(&cp, dom, strlen(lbuf)) <= 0)
-               goto out;
-       if (qword_get(&cp, path, strlen(lbuf)) <= 0)
-               goto out;
+static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he)
+{
+       return path_matches(exp, path) && client_matches(exp, dom, he);
+}
 
-       auth_reload();
+static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
+{
+       nfs_export *exp;
+       nfs_export *found = NULL;
+       int found_type = 0;
+       int i;
 
-       /* now find flags for this export point in this domain */
        for (i=0 ; i < MCL_MAXTYPES; i++) {
                for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
-                       if (!use_ipaddr && !client_member(dom, exp->m_client->m_hostname))
-                               continue;
-                       if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
-                               /* if path is a mountpoint below e_path, then OK */
-                               int l = strlen(exp->m_export.e_path);
-                               if (strcmp(path, exp->m_export.e_path) == 0 ||
-                                   (strncmp(path, exp->m_export.e_path, l) == 0 &&
-                                    path[l] == '/' &&
-                                    is_mountpoint(path)))
-                                       /* ok */;
-                               else
-                                       continue;
-                       } else if (strcmp(path, exp->m_export.e_path) != 0)
+                       if (!export_matches(exp, dom, path, he))
                                continue;
-                       if (use_ipaddr) {
-                               if (he == NULL) {
-                                       if (!inet_aton(dom, &addr))
-                                               goto out;
-                                       he = client_resolve(addr);
-                               }
-                               if (!client_check(exp->m_client, he))
-                                       continue;
-                       }
                        if (!found) {
                                found = exp;
                                found_type = i;
                                continue;
                        }
+
+                       /* Always prefer non-V4ROOT mounts */
+                       if (found->m_export.e_flags & NFSEXP_V4ROOT)
+                               continue;
+
                        /* If one is a CROSSMOUNT, then prefer the longest path */
                        if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) ||
                             (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) &&
@@ -703,6 +684,50 @@ void nfsd_export(FILE *f)
                        }
                }
        }
+       return found;
+}
+
+void nfsd_export(FILE *f)
+{
+       /* requests are:
+        *  domain path
+        * determine export options and return:
+        *  domain path expiry flags anonuid anongid fsid
+        */
+
+       char *cp;
+       char *dom, *path;
+       nfs_export *found = NULL;
+       struct in_addr addr;
+       struct hostent *he = NULL;
+
+
+       if (readline(fileno(f), &lbuf, &lbuflen) != 1)
+               return;
+
+       xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf);
+
+       cp = lbuf;
+       dom = malloc(strlen(cp));
+       path = malloc(strlen(cp));
+
+       if (!dom || !path)
+               goto out;
+
+       if (qword_get(&cp, dom, strlen(lbuf)) <= 0)
+               goto out;
+       if (qword_get(&cp, path, strlen(lbuf)) <= 0)
+               goto out;
+
+       auth_reload();
+
+       if (use_ipaddr) {
+               if (!inet_aton(dom, &addr))
+                       goto out;
+               he = client_resolve(addr);
+       }
+
+       found = lookup_export(dom, path, he);
 
        if (found) {
                if (dump_to_cache(f, dom, path, &found->m_export) < 0) {
index 199fcece4f4682fb51e27dff87e42847b2096a47..ba6981defd9456c9621e08b2074ce947a45860c0 100644 (file)
@@ -70,12 +70,10 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
 {
        union mountd_arguments  argument;
        union mountd_results    result;
-#ifdef HAVE_TCP_WRAPPER
-       struct sockaddr_in *sin = nfs_getrpccaller_in(transp);
 
+#ifdef HAVE_TCP_WRAPPER
        /* remote host authorization check */
-       if (sin->sin_family == AF_INET &&
-           !check_default("mountd", sin, rqstp->rq_proc, MOUNTPROG)) {
+       if (!check_default("mountd", nfs_getrpccaller(transp), MOUNTPROG)) {
                svcerr_auth (transp, AUTH_FAILED);
                return;
        }
index 888fd8c92b3da19a42e3964407c680415ccfbe89..a0a1f2d03a7c61c5b339bd72498abbe8fac9bde3 100644 (file)
@@ -509,12 +509,89 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
        return fh;
 }
 
+static void remove_all_clients(exportnode *e)
+{
+       struct groupnode *g, *ng;
+
+       for (g = e->ex_groups; g; g = ng) {
+               ng = g->gr_next;
+               xfree(g->gr_name);
+               xfree(g);
+       }
+       e->ex_groups = NULL;
+}
+
+static void free_exportlist(exports *elist)
+{
+       struct exportnode *e, *ne;
+
+       for (e = *elist; e != NULL; e = ne) {
+               ne = e->ex_next;
+               remove_all_clients(e);
+               xfree(e->ex_dir);
+               xfree(e);
+       }
+       *elist = NULL;
+}
+
+static void prune_clients(nfs_export *exp, struct exportnode *e)
+{
+       struct hostent  *hp;
+       struct groupnode *c, **cp;
+
+       cp = &e->ex_groups;
+       while ((c = *cp) != NULL) {
+               if (client_gettype(c->gr_name) == MCL_FQDN
+                               && (hp = gethostbyname(c->gr_name))) {
+                       hp = hostent_dup(hp);
+                       if (client_check(exp->m_client, hp)) {
+                               *cp = c->gr_next;
+                               xfree(c->gr_name);
+                               xfree(c);
+                               xfree (hp);
+                               continue;
+                       }
+                       xfree (hp);
+               }
+               cp = &(c->gr_next);
+       }
+}
+
+static exportnode *lookup_or_create_elist_entry(exports *elist, nfs_export *exp)
+{
+       exportnode *e;
+
+       for (e = *elist; e != NULL; e = e->ex_next) {
+               if (!strcmp(exp->m_export.e_path, e->ex_dir))
+                       return e;
+       }
+       e = xmalloc(sizeof(*e));
+       e->ex_next = *elist;
+       e->ex_groups = NULL;
+       e->ex_dir = xstrdup(exp->m_export.e_path);
+       *elist = e;
+       return e;
+}
+
+static void insert_group(struct exportnode *e, char *newname)
+{
+       struct groupnode *g;
+
+       for (g = e->ex_groups; g; g = g->gr_next)
+               if (strcmp(g->gr_name, newname))
+                       return;
+
+       g = xmalloc(sizeof(*g));
+       g->gr_name = xstrdup(newname);
+       g->gr_next = e->ex_groups;
+       e->ex_groups = g;
+}
+
 static exports
 get_exportlist(void)
 {
        static exports          elist = NULL;
-       struct exportnode       *e, *ne;
-       struct groupnode        *g, *ng, *c, **cp;
+       struct exportnode       *e;
        nfs_export              *exp;
        int                     i;
        static unsigned int     ecounter;
@@ -526,77 +603,26 @@ get_exportlist(void)
 
        ecounter = acounter;
 
-       for (e = elist; e != NULL; e = ne) {
-               ne = e->ex_next;
-               for (g = e->ex_groups; g != NULL; g = ng) {
-                       ng = g->gr_next;
-                       xfree(g->gr_name);
-                       xfree(g);
-               }
-               xfree(e->ex_dir);
-               xfree(e);
-       }
-       elist = NULL;
+       free_exportlist(&elist);
 
        for (i = 0; i < MCL_MAXTYPES; i++) {
                for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
-                       for (e = elist; e != NULL; e = e->ex_next) {
-                               if (!strcmp(exp->m_export.e_path, e->ex_dir))
-                                       break;
-                       }
-                       if (!e) {
-                               e = (struct exportnode *) xmalloc(sizeof(*e));
-                               e->ex_next = elist;
-                               e->ex_groups = NULL;
-                               e->ex_dir = xstrdup(exp->m_export.e_path);
-                               elist = e;
-                       }
-
-                       /* We need to check if we should remove
-                          previous ones. */
-                       if (i == MCL_ANONYMOUS && e->ex_groups) {
-                               for (g = e->ex_groups; g; g = ng) {
-                                       ng = g->gr_next;
-                                       xfree(g->gr_name);
-                                       xfree(g);
-                               }
-                               e->ex_groups = NULL;
+                        /* Don't show pseudo exports */
+                       if (exp->m_export.e_flags & NFSEXP_V4ROOT)
                                continue;
-                       }
-
-                       if (i != MCL_FQDN && e->ex_groups) {
-                         struct hostent        *hp;
+                       e = lookup_or_create_elist_entry(&elist, exp);
 
-                         cp = &e->ex_groups;
-                         while ((c = *cp) != NULL) {
-                           if (client_gettype (c->gr_name) == MCL_FQDN
-                               && (hp = gethostbyname(c->gr_name))) {
-                             hp = hostent_dup (hp);
-                             if (client_check(exp->m_client, hp)) {
-                               *cp = c->gr_next;
-                               xfree(c->gr_name);
-                               xfree(c);
-                               xfree (hp);
+                       /* exports to "*" absorb any others */
+                       if (i == MCL_ANONYMOUS && e->ex_groups) {
+                               remove_all_clients(e);
                                continue;
-                             }
-                             xfree (hp);
-                           }
-                           cp = &(c->gr_next);
-                         }
                        }
+                       /* non-FQDN's absorb FQDN's they contain: */
+                       if (i != MCL_FQDN && e->ex_groups)
+                               prune_clients(exp, e);
 
-                       if (exp->m_export.e_hostname [0] != '\0') {
-                               for (g = e->ex_groups; g; g = g->gr_next)
-                                       if (strcmp (exp->m_export.e_hostname,
-                                                   g->gr_name) == 0)
-                                               break;
-                               if (g)
-                                       continue;
-                               g = (struct groupnode *) xmalloc(sizeof(*g));
-                               g->gr_name = xstrdup(exp->m_export.e_hostname);
-                               g->gr_next = e->ex_groups;
-                               e->ex_groups = g;
-                       }
+                       if (exp->m_export.e_hostname[0] != '\0')
+                               insert_group(e, exp->m_export.e_hostname);
                }
        }
 
index c371f8db8bef27bd8d9dd5e98807d026e754122d..19b22eea280d2028dd607ae5911c9687e91fc588 100644 (file)
@@ -24,6 +24,7 @@
 #include "ha-callout.h"
 
 #include <limits.h> /* PATH_MAX */
+#include <errno.h>
 
 extern int reverse_resolve;
 
@@ -143,23 +144,16 @@ mountlist_del_all(struct sockaddr_in *sin)
                return;
        if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) {
                xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr));
-               xfunlock(lockid);
-               return;
+               goto out_unlock;
        }
-       else
-               hp = hostent_dup (hp);
+       hp = hostent_dup (hp);
+
+       if (!setrmtabent("r"))
+               goto out_free;
+
+       if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w")))
+               goto out_close;
 
-       if (!setrmtabent("r")) {
-               xfunlock(lockid);
-               free (hp);
-               return;
-       }
-       if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) {
-               endrmtabent();
-               xfunlock(lockid);
-               free (hp);
-               return;
-       }
        while ((rep = getrmtabent(1, NULL)) != NULL) {
                if (strcmp(rep->r_client, hp->h_name) == 0 &&
                    (exp = auth_authenticate("umountall", sin, rep->r_path)))
@@ -170,10 +164,13 @@ mountlist_del_all(struct sockaddr_in *sin)
                xlog(L_ERROR, "couldn't rename %s to %s",
                                _PATH_RMTABTMP, _PATH_RMTAB);
        }
-       endrmtabent();  /* close & unlink */
        fendrmtabent(fp);
-       xfunlock(lockid);
+out_close:
+       endrmtabent();  /* close & unlink */
+out_free:
        free (hp);
+out_unlock:
+       xfunlock(lockid);
 }
 
 mountlist
@@ -191,7 +188,9 @@ mountlist_list(void)
        if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
                return NULL;
        if (stat(_PATH_RMTAB, &stb) < 0) {
-               xlog(L_ERROR, "can't stat %s", _PATH_RMTAB);
+               xlog(L_ERROR, "can't stat %s: %s",
+                               _PATH_RMTAB, strerror(errno));
+               xfunlock(lockid);
                return NULL;
        }
        if (stb.st_mtime != last_mtime) {
diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c
new file mode 100644 (file)
index 0000000..7fd6af3
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ *
+ * support/export/v4root.c
+ *
+ * Routines used to support NFSv4 pseudo roots
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "xlog.h"
+#include "exportfs.h"
+#include "nfslib.h"
+#include "misc.h"
+#include "v4root.h"
+
+int v4root_needed;
+
+static nfs_export pseudo_root = {
+       .m_next = NULL,
+       .m_client = NULL,
+       .m_export = {
+               .e_hostname = "*",
+               .e_path = "/",
+               .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
+                               | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
+                               | NFSEXP_V4ROOT,
+               .e_anonuid = 65534,
+               .e_anongid = 65534,
+               .e_squids = NULL,
+               .e_nsquids = 0,
+               .e_sqgids = NULL,
+               .e_nsqgids = 0,
+               .e_fsid = 0,
+               .e_mountpoint = NULL,
+       },
+       .m_exported = 0,
+       .m_xtabent = 1,
+       .m_mayexport = 1,
+       .m_changed = 0,
+       .m_warned = 0,
+};
+
+void set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
+{
+       struct sec_entry *se;
+       int i;
+
+       if (source->e_flags & NFSEXP_INSECURE_PORT)
+               pseudo->e_flags |= NFSEXP_INSECURE_PORT;
+       for (se = source->e_secinfo; se->flav; se++) {
+               struct sec_entry *new;
+
+               i = secinfo_addflavor(se->flav, pseudo);
+               new = &pseudo->e_secinfo[i];
+
+               if (se->flags & NFSEXP_INSECURE_PORT)
+                       new->flags |= NFSEXP_INSECURE_PORT;
+       }
+}
+
+/*
+ * Create a pseudo export
+ */
+static struct exportent *
+v4root_create(char *path, nfs_export *export)
+{
+       nfs_export *exp;
+       struct exportent eep;
+       struct exportent *curexp = &export->m_export;
+
+       dupexportent(&eep, &pseudo_root.m_export);
+       eep.e_hostname = strdup(curexp->e_hostname);
+       strncpy(eep.e_path, path, sizeof(eep.e_path));
+       if (strcmp(path, "/") != 0)
+               eep.e_flags &= ~NFSEXP_FSID;
+       set_pseudofs_security(&eep, curexp);
+       exp = export_create(&eep, 0);
+       if (exp == NULL)
+               return NULL;
+       xlog(D_CALL, "v4root_create: path '%s'", exp->m_export.e_path);
+       return &exp->m_export;
+}
+
+/*
+ * Make sure the kernel has pseudo root support.
+ */
+static int
+v4root_support(void)
+{
+       struct export_features *ef;
+       static int warned = 0;
+
+       ef = get_export_features();
+
+       if (ef->flags & NFSEXP_V4ROOT)
+               return 1;
+       if (!warned) {
+               xlog(L_WARNING, "Kernel does not have pseudo root support.");
+               xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
+               xlog(L_WARNING, "is specfied in /etc/exports file.");
+               warned++;
+       }
+       return 0;
+}
+
+int pseudofs_update(char *hostname, char *path, nfs_export *source)
+{
+       nfs_export *exp;
+
+       exp = export_lookup(hostname, path, 0);
+       if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
+               return 0;
+       if (!exp) {
+               if (v4root_create(path, source) == NULL) {
+                       xlog(L_WARNING, "v4root_set: Unable to create "
+                                       "pseudo export for '%s'", path);
+                       return -ENOMEM;
+               }
+               return 0;
+       }
+       /* Update an existing V4ROOT export: */
+       set_pseudofs_security(&exp->m_export, &source->m_export);
+       return 0;
+}
+
+static int v4root_add_parents(nfs_export *exp)
+{
+       char *hostname = exp->m_export.e_hostname;
+       char *path;
+       char *ptr;
+
+       path = strdup(exp->m_export.e_path);
+       if (!path)
+               return -ENOMEM;
+       for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) {
+               int ret;
+               char saved;
+
+               saved = *ptr;
+               *ptr = '\0';
+               ret = pseudofs_update(hostname, path, exp);
+               if (ret)
+                       return ret;
+               *ptr = saved;
+               ptr++;
+       }
+       free(path);
+       return 0;
+}
+
+/*
+ * Create pseudo exports by running through the real export
+ * looking at the components of the path that make up the export.
+ * Those path components, if not exported, will become pseudo
+ * exports allowing them to be found when the kernel does an upcall
+ * looking for components of the v4 mount.
+ */
+void
+v4root_set()
+{
+       nfs_export      *exp;
+       int     i, ret;
+
+       if (!v4root_needed)
+               return;
+       if (!v4root_support())
+               return;
+
+       for (i = 0; i < MCL_MAXTYPES; i++) {
+               for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+                       if (exp->m_export.e_flags & NFSEXP_V4ROOT)
+                               /*
+                                * We just added this one, so its
+                                * parents are already dealt with!
+                                */
+                               continue;
+
+                       ret = v4root_add_parents(exp);
+                       /* XXX: error handling! */
+               }
+       }
+}
index b7d91eac0347bbaeaea95fd0328c38c8ab101d9d..6c87badc4bcdd03327793ec1efeaf6e8fcf0a5f4 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -160,6 +161,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -226,6 +228,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 12d3253228fadb0e074590b83d6e08808c2ec59e..60232b88a935943a67fe55a38d4796fcab0b154b 100644 (file)
@@ -212,7 +212,7 @@ int
 nfssvc_set_sockets(const int family, const unsigned int protobits,
                   const char *host, const char *port)
 {
-       struct addrinfo hints = { .ai_flags = AI_PASSIVE | AI_ADDRCONFIG };
+       struct addrinfo hints = { .ai_flags = AI_PASSIVE };
 
        hints.ai_family = family;
 
@@ -238,17 +238,17 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers4)
        if (fd < 0)
                return;
 
+       n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
+       if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
+                   off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d ",
+                                   minorvers4 > 0 ? '+' : '-',
+                                   n);
        for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
                if (NFSCTL_VERISSET(ctlbits, n))
                    off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
                else
                    off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
        }
-       n = minorvers4 >= 0 ? minorvers4 : -minorvers4;
-       if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4)
-                   off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d",
-                                   minorvers4 > 0 ? '+' : '-',
-                                   n);
        xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
        snprintf(ptr+off, sizeof(buf) - off, "\n");
        if (write(fd, buf, strlen(buf)) != strlen(buf))
index 69e6e2d42be4aaa9ece877fc879fc38427398c08..fd147bb153f88c081efa6935ba64bc676b82ce68 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -161,6 +162,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -227,6 +229,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index fa46d5d26516021a07273a1ebf13d9e0a5be8a5b..99d77c962174f26b68157abaad9f1dce8a47c037 100644 (file)
 
 #define MAXNRVALS      32
 
-static unsigned int    srvproc2info[20], srvproc2info_old[20]; /* NFSv2 call counts ([0] == 18) */
-static unsigned int    cltproc2info[20], cltproc2info_old[20]; /* NFSv2 call counts ([0] == 18) */
-static unsigned int    srvproc3info[24], srvproc3info_old[24]; /* NFSv3 call counts ([0] == 22) */
-static unsigned int    cltproc3info[24], cltproc3info_old[24]; /* NFSv3 call counts ([0] == 22) */
-static unsigned int    srvproc4info[4], srvproc4info_old[4];   /* NFSv4 call counts ([0] == 2) */
-static unsigned int    cltproc4info[49], cltproc4info_old[49]; /* NFSv4 call counts ([0] == 35) */
-static unsigned int    srvproc4opsinfo[61], srvproc4opsinfo_old[61];   /* NFSv4 call counts ([0] == 40) */
+enum {
+       SRVPROC2_SZ = 18,
+       CLTPROC2_SZ = 18,
+       SRVPROC3_SZ = 22,
+       CLTPROC3_SZ = 22,
+       SRVPROC4_SZ = 2,
+       CLTPROC4_SZ = 48,
+       SRVPROC4OPS_SZ = 59,
+};
+
+static unsigned int    srvproc2info[SRVPROC2_SZ+2],
+                       srvproc2info_old[SRVPROC2_SZ+2];        /* NFSv2 call counts ([0] == 18) */
+static unsigned int    cltproc2info[CLTPROC2_SZ+2],
+                       cltproc2info_old[CLTPROC2_SZ+2];        /* NFSv2 call counts ([0] == 18) */
+static unsigned int    srvproc3info[SRVPROC3_SZ+2],
+                       srvproc3info_old[SRVPROC3_SZ+2];        /* NFSv3 call counts ([0] == 22) */
+static unsigned int    cltproc3info[CLTPROC3_SZ+2],
+                       cltproc3info_old[CLTPROC3_SZ+2];        /* NFSv3 call counts ([0] == 22) */
+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) */
+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
                                                                 * 1  UDP packets
                                                                 * 2  TCP packets
@@ -75,25 +92,25 @@ static unsigned int srvfhinfo[7], srvfhinfo_old[7];         /* (for kernels >= 2.4.0)
                                                                 *    compatability.
                                                                 */
 
-static const char *    nfsv2name[18] = {
+static const char *    nfsv2name[SRVPROC2_SZ] = {
        "null", "getattr", "setattr", "root",   "lookup",  "readlink",
        "read", "wrcache", "write",   "create", "remove",  "rename",
        "link", "symlink", "mkdir",   "rmdir",  "readdir", "fsstat"
 };
 
-static const char *    nfsv3name[22] = {
+static const char *    nfsv3name[SRVPROC3_SZ] = {
        "null",   "getattr", "setattr",  "lookup", "access",  "readlink",
        "read",   "write",   "create",   "mkdir",  "symlink", "mknod",
        "remove", "rmdir",   "rename",   "link",   "readdir", "readdirplus",
        "fsstat", "fsinfo",  "pathconf", "commit"
 };
 
-static const char *    nfssrvproc4name[2] = {
+static const char *    nfssrvproc4name[SRVPROC4_SZ] = {
        "null",
        "compound",
 };
 
-static const char *    nfscltproc4name[47] = {
+static const char *    nfscltproc4name[CLTPROC4_SZ] = {
        "null",      "read",      "write",   "commit",      "open",        "open_conf",
        "open_noat", "open_dgrd", "close",   "setattr",     "fsinfo",      "renew",
        "setclntid", "confirm",   "lock",
@@ -107,6 +124,7 @@ static const char * nfscltproc4name[47] = {
        "destroy_ses",
        "sequence",
        "get_lease_t",
+       "reclaim_comp",
        "layoutget",
        "layoutcommit",
        "layoutreturn",
@@ -117,7 +135,7 @@ static const char * nfscltproc4name[47] = {
        "ds_commit",
 };
 
-static const char *     nfssrvproc4opname[59] = {
+static const char *     nfssrvproc4opname[SRVPROC4OPS_SZ] = {
         "op0-unused",   "op1-unused", "op2-future",  "access",     "close",       "commit",
         "create",       "delegpurge", "delegreturn", "getattr",    "getfh",       "link",
         "lock",         "lockt",      "locku",       "lookup",     "lookup_root", "nverify",
index b342bb8e296deab94f89795851a50f046a7b1c48..8eeae8eb3515ad3fa1dbcff0ab1743dacff03a77 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -42,6 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -161,6 +162,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -227,6 +229,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
index 418e8b9e4f9d3d233dda3a241f1fa69e2d58582d..f567093c7dafd8a6afa34ab894ed028b8833984c 100644 (file)
@@ -78,29 +78,36 @@ static void usage(FILE *fp, int n)
        exit(n);
 }
 
-static const char *nfs_sm_pgmtbl[] = {
+static const char *mount_pgm_tbl[] = {
        "showmount",
        "mount",
        "mountd",
        NULL,
 };
 
+static const rpcvers_t mount_vers_tbl[] = {
+       MOUNTVERS_NFSV3,
+       MOUNTVERS_POSIX,
+       MOUNTVERS,
+};
+static const unsigned int max_vers_tblsz = 
+       (sizeof(mount_vers_tbl)/sizeof(mount_vers_tbl[0]));
+
 /*
  * Generate an RPC client handle connected to the mountd service
  * at @hostname, or die trying.
  *
  * Supports both AF_INET and AF_INET6 server addresses.
  */
-static CLIENT *nfs_get_mount_client(const char *hostname)
+static CLIENT *nfs_get_mount_client(const char *hostname, rpcvers_t vers)
 {
-       rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, nfs_sm_pgmtbl);
+       rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, mount_pgm_tbl);
        CLIENT *client;
 
-       client = clnt_create(hostname, program, MOUNTVERS, "tcp");
+       client = clnt_create(hostname, program, vers, "tcp");
        if (client)
                return client;
-
-       client = clnt_create(hostname, program, MOUNTVERS, "udp");
+       client = clnt_create(hostname, program, vers, "udp");
        if (client)
                return client;
 
@@ -123,6 +130,7 @@ int main(int argc, char **argv)
        int i;
        int n;
        int maxlen;
+       int unsigned vers=0;
        char **dumpv;
 
        program_name = argv[0];
@@ -185,11 +193,12 @@ int main(int argc, char **argv)
                break;
        }
 
-       mclient = nfs_get_mount_client(hostname);
+       mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
        mclient->cl_auth = authunix_create_default();
        total_timeout.tv_sec = TOTAL_TIMEOUT;
        total_timeout.tv_usec = 0;
 
+again:
        if (eflag) {
                memset(&exportlist, '\0', sizeof(exportlist));
 
@@ -197,6 +206,13 @@ int main(int argc, char **argv)
                        (xdrproc_t) xdr_void, NULL,
                        (xdrproc_t) xdr_exports, (caddr_t) &exportlist,
                        total_timeout);
+               if (clnt_stat == RPC_PROGVERSMISMATCH) {
+                       if (++vers <  max_vers_tblsz) {
+                               (void)CLNT_CONTROL(mclient, CLSET_VERS, 
+                                       (void *)&mount_vers_tbl[vers]);
+                               goto again;
+                               }
+               }
                if (clnt_stat != RPC_SUCCESS) {
                        clnt_perror(mclient, "rpc mount export");
                        clnt_destroy(mclient);
@@ -232,6 +248,13 @@ int main(int argc, char **argv)
                (xdrproc_t) xdr_void, NULL,
                (xdrproc_t) xdr_mountlist, (caddr_t) &dumplist,
                total_timeout);
+       if (clnt_stat == RPC_PROGVERSMISMATCH) {
+               if (++vers <  max_vers_tblsz) {
+                       (void)CLNT_CONTROL(mclient, CLSET_VERS, 
+                               (void *)&mount_vers_tbl[vers]);
+                       goto again;
+               }
+       }
        if (clnt_stat != RPC_SUCCESS) {
                clnt_perror(mclient, "rpc mount dump");
                clnt_destroy(mclient);
index 8a3ba4ede06ced52f9ccddba35d52e79a2947f50..17447914aa69c3066e7dda1b1ae5fb376072bf37 100644 (file)
@@ -2,31 +2,25 @@
 
 man8_MANS = statd.man sm-notify.man
 
-GENFILES_CLNT  = sm_inter_clnt.c
-GENFILES_SVC   = sm_inter_svc.c
-GENFILES_XDR   = sm_inter_xdr.c
-GENFILES_H     = sm_inter.h
-
-GENFILES       = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
-
 RPCPREFIX      = rpc.
 KPREFIX                = @kprefix@
 sbin_PROGRAMS  = statd sm-notify
 dist_sbin_SCRIPTS      = start-statd
-statd_SOURCES = callback.c notlist.c log.c misc.c monitor.c \
+statd_SOURCES = callback.c notlist.c misc.c monitor.c hostname.c \
                simu.c stat.c statd.c svc_run.c rmtcall.c \
-               sm_inter_clnt.c sm_inter_svc.c sm_inter_xdr.c log.h \
-               notlist.h statd.h system.h version.h sm_inter.h
+               notlist.h statd.h system.h version.h
 sm_notify_SOURCES = sm-notify.c
 
 BUILT_SOURCES = $(GENFILES)
-statd_LDADD = ../../support/export/libexport.a \
+statd_LDADD = ../../support/nsm/libnsm.a \
              ../../support/nfs/libnfs.a \
              ../../support/misc/libmisc.a \
-             $(LIBWRAP) $(LIBNSL)
-sm_notify_LDADD = $(LIBNSL)
+             $(LIBWRAP) $(LIBNSL) $(LIBCAP)
+sm_notify_LDADD = ../../support/nsm/libnsm.a \
+                 ../../support/nfs/libnfs.a \
+                 $(LIBNSL) $(LIBCAP)
 
-EXTRA_DIST = sim_sm_inter.x sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
+EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
 
 if CONFIG_RPCGEN
 RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
index c158d82ec077120325c4ff9b3431b1b00d1bd981..ff9d37df39c8351ee91c8647eb29530cce511271 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -44,6 +44,7 @@ am__aclocal_m4_deps = $(top_srcdir)/aclocal/bsdsignals.m4 \
        $(top_srcdir)/aclocal/ipv6.m4 \
        $(top_srcdir)/aclocal/kerberos5.m4 \
        $(top_srcdir)/aclocal/libblkid.m4 \
+       $(top_srcdir)/aclocal/libcap.m4 \
        $(top_srcdir)/aclocal/libevent.m4 \
        $(top_srcdir)/aclocal/libnfsidmap.m4 \
        $(top_srcdir)/aclocal/librpcsecgss.m4 \
@@ -64,16 +65,18 @@ PROGRAMS = $(sbin_PROGRAMS)
 am_sm_notify_OBJECTS = sm-notify.$(OBJEXT)
 sm_notify_OBJECTS = $(am_sm_notify_OBJECTS)
 am__DEPENDENCIES_1 =
-sm_notify_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am_statd_OBJECTS = callback.$(OBJEXT) notlist.$(OBJEXT) log.$(OBJEXT) \
-       misc.$(OBJEXT) monitor.$(OBJEXT) simu.$(OBJEXT) stat.$(OBJEXT) \
-       statd.$(OBJEXT) svc_run.$(OBJEXT) rmtcall.$(OBJEXT) \
-       sm_inter_clnt.$(OBJEXT) sm_inter_svc.$(OBJEXT) \
-       sm_inter_xdr.$(OBJEXT)
+sm_notify_DEPENDENCIES = ../../support/nsm/libnsm.a \
+       ../../support/nfs/libnfs.a $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
+am_statd_OBJECTS = callback.$(OBJEXT) notlist.$(OBJEXT) misc.$(OBJEXT) \
+       monitor.$(OBJEXT) hostname.$(OBJEXT) simu.$(OBJEXT) \
+       stat.$(OBJEXT) statd.$(OBJEXT) svc_run.$(OBJEXT) \
+       rmtcall.$(OBJEXT)
 statd_OBJECTS = $(am_statd_OBJECTS)
-statd_DEPENDENCIES = ../../support/export/libexport.a \
+statd_DEPENDENCIES = ../../support/nsm/libnsm.a \
        ../../support/nfs/libnfs.a ../../support/misc/libmisc.a \
-       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -174,6 +177,7 @@ LDFLAGS = @LDFLAGS@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LIBBLKID = @LIBBLKID@
 LIBBSD = @LIBBSD@
+LIBCAP = @LIBCAP@
 LIBCRYPT = @LIBCRYPT@
 LIBNSL = @LIBNSL@
 LIBOBJS = @LIBOBJS@
@@ -240,6 +244,7 @@ enable_ipv6 = @enable_ipv6@
 enable_mountconfig = @enable_mountconfig@
 enable_nfsv3 = @enable_nfsv3@
 enable_nfsv4 = @enable_nfsv4@
+enable_nfsv41 = @enable_nfsv41@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -276,28 +281,25 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 man8_MANS = statd.man sm-notify.man
-GENFILES_CLNT = sm_inter_clnt.c
-GENFILES_SVC = sm_inter_svc.c
-GENFILES_XDR = sm_inter_xdr.c
-GENFILES_H = sm_inter.h
-GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
 RPCPREFIX = rpc.
 KPREFIX = @kprefix@
 dist_sbin_SCRIPTS = start-statd
-statd_SOURCES = callback.c notlist.c log.c misc.c monitor.c \
+statd_SOURCES = callback.c notlist.c misc.c monitor.c hostname.c \
                simu.c stat.c statd.c svc_run.c rmtcall.c \
-               sm_inter_clnt.c sm_inter_svc.c sm_inter_xdr.c log.h \
-               notlist.h statd.h system.h version.h sm_inter.h
+               notlist.h statd.h system.h version.h
 
 sm_notify_SOURCES = sm-notify.c
 BUILT_SOURCES = $(GENFILES)
-statd_LDADD = ../../support/export/libexport.a \
+statd_LDADD = ../../support/nsm/libnsm.a \
              ../../support/nfs/libnfs.a \
              ../../support/misc/libmisc.a \
-             $(LIBWRAP) $(LIBNSL)
+             $(LIBWRAP) $(LIBNSL) $(LIBCAP)
 
-sm_notify_LDADD = $(LIBNSL)
-EXTRA_DIST = sim_sm_inter.x sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
+sm_notify_LDADD = ../../support/nsm/libnsm.a \
+                 ../../support/nfs/libnfs.a \
+                 $(LIBNSL) $(LIBCAP)
+
+EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
 @CONFIG_RPCGEN_FALSE@RPCGEN = @RPCGEN_PATH@
 @CONFIG_RPCGEN_TRUE@RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
 MAINTAINERCLEANFILES = Makefile.in
@@ -428,16 +430,13 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostname.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/monitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notlist.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rmtcall.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simu.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm-notify.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_clnt.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_svc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_xdr.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svc_run.Po@am__quote@
index 888523872931055c70e6bbac39d1778a4c31d1fd..d1cc139992734476b25233fd117716d6775d3485 100644 (file)
 #include <config.h>
 #endif
 
-#include <arpa/inet.h>
+#include <netdb.h>
 
 #include "rpcmisc.h"
-#include "misc.h"
 #include "statd.h"
 #include "notlist.h"
 
 /* notify_list *cbnl = NULL; ... never used */
 
 
-/* 
+/*
  * Services SM_NOTIFY requests.
- * Any clients that have asked us to monitor that host are put on
- * the global callback list, which is processed as soon as statd
- * returns to svc_run.
+ *
+ * When NLM uses an SM_MON request to tell statd to monitor a remote,
+ * the request contains a "mon_name" argument.  This is usually the
+ * "caller_name" argument of an NLMPROC_LOCK request.  On Linux, the
+ * NLM can send statd the remote's IP address instead of its
+ * caller_name.  The NSM protocol does not allow both the remote's
+ * caller_name and it's IP address to be sent in the same SM_MON
+ * request.
+ *
+ * The remote's caller_name is useful because it makes it simple
+ * to identify rebooting remotes by matching the "mon_name" argument
+ * they sent via an SM_NOTIFY request.
+ *
+ * The caller_name string may not be a fully qualified domain name,
+ * or even registered in the DNS database, however.  Having the
+ * remote's IP address is useful because then there is no ambiguity
+ * about where to send an SM_NOTIFY after the local system reboots.
+ *
+ * Without the actual caller_name, however, statd must use an
+ * heuristic to match an incoming SM_NOTIFY request to one of the
+ * hosts it is currently monitoring.  The incoming mon_name in an
+ * SM_NOTIFY address is converted to a list of IP addresses using
+ * DNS.  Each mon_name on statd's monitor list is also converted to
+ * an address list, and the two lists are checked to see if there is
+ * a matching address.
+ *
+ * There are some risks to this strategy:
+ *
+ *   1.  The external DNS database is not reliable.  It can change
+ *       over time, or the forward and reverse mappings could be
+ *       inconsistent.
+ *
+ *   2.  If statd's monitor list becomes substantial, finding a match
+ *       can generate a not inconsequential amount of DNS traffic.
+ *
+ *   3.  statd is a single-threaded service.  When DNS becomes slow or
+ *       unresponsive, statd also becomes slow or unresponsive.
+ *
+ *   4.  If the remote does not have a DNS entry at all (or if the
+ *       remote can resolve itself, but the local host can't resolve
+ *       the remote's hostname), the remote cannot be monitored, and
+ *       therefore NLM locking cannot be provided for that host.
+ *
+ *   5.  Local DNS resolution can produce different results for the
+ *       mon_name than the results the remote might see for the same
+ *       query, especially if the remote did not send a caller_name
+ *       or mon_name that is a fully qualified domain name.
+ *
+ *       Note that a caller_name is passed from NFS client to server,
+ *       but the client never knows what mon_name the server might use
+ *       to notify it of a reboot.  On Linux, the client extracts the
+ *       server's name from the devname it was passed by the mount
+ *       command.  This is often not a fully-qualified domain name.
  */
 void *
 sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp)
 {
        notify_list    *lp, *call;
        static char    *result = NULL;
-       struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
-       char *ip_addr = xstrdup(inet_ntoa(sin->sin_addr));
+       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
+       char            ip_addr[INET6_ADDRSTRLEN];
 
-       dprintf(N_DEBUG, "Received SM_NOTIFY from %s, state: %d",
+       xlog(D_CALL, "Received SM_NOTIFY from %s, state: %d",
                                argp->mon_name, argp->state);
 
        /* quick check - don't bother if we're not monitoring anyone */
        if (rtnl == NULL) {
-               note(N_WARNING, "SM_NOTIFY from %s while not monitoring any hosts.",
+               xlog_warn("SM_NOTIFY from %s while not monitoring any hosts",
                                argp->mon_name);
                return ((void *) &result);
        }
 
+       if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) {
+               xlog_warn("Unrecognized sender address");
+               return ((void *) &result);
+       }
+
        /* okir change: statd doesn't remove the remote host from its
         * internal monitor list when receiving an SM_NOTIFY call from
         * it. Lockd will want to continue monitoring the remote host
@@ -52,8 +106,8 @@ sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp)
         */
        for (lp = rtnl ; lp ; lp = lp->next)
                if (NL_STATE(lp) != argp->state &&
-                   (matchhostname(argp->mon_name, lp->dns_name) ||
-                    matchhostname(ip_addr, lp->dns_name))) {
+                   (statd_matchhostname(argp->mon_name, lp->dns_name) ||
+                    statd_matchhostname(ip_addr, lp->dns_name))) {
                        NL_STATE(lp) = argp->state;
                        call = nlist_clone(lp);
                        nlist_insert(&notify, call);
diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c
new file mode 100644 (file)
index 0000000..7d704cc
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "sockaddr.h"
+#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
+ * @buf: pointer to buffer to fill in
+ * @buflen: length of buffer
+ *
+ * Convert the passed-in sockaddr-style address to presentation format.
+ * The presentation format address is placed in @buf and is
+ * '\0'-terminated.
+ *
+ * Returns true if successful; otherwise false.
+ *
+ * getnameinfo(3) is preferred, since it can parse IPv6 scope IDs.
+ * An alternate version of statd_present_address() is available to
+ * handle older glibcs that do not have getnameinfo(3).
+ */
+#ifdef HAVE_GETNAMEINFO
+_Bool
+statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
+{
+       socklen_t salen;
+       int error;
+
+       salen = nfs_sockaddr_length(sap);
+       if (salen == 0) {
+               xlog(D_GENERAL, "%s: unsupported address family",
+                               __func__);
+               return false;
+       }
+
+       error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
+                                               NULL, 0, NI_NUMERICHOST);
+       if (error != 0) {
+               xlog(D_GENERAL, "%s: getnameinfo(3): %s",
+                               __func__, gai_strerror(error));
+               return false;
+       }
+       return true;
+}
+#else  /* !HAVE_GETNAMEINFO */
+_Bool
+statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+
+       if (sin->sin_family != AF_INET) {
+               xlog(D_GENERAL, "%s: unsupported address family", __func__);
+               return false;
+       }
+
+       /* ensure '\0' termination */
+       memset(buf, 0, buflen);
+
+       if (inet_ntop(AF_INET, (char *)&sin->sin_addr,
+                                       buf, (socklen_t)buflen) == NULL) {
+               xlog(D_GENERAL, "%s: inet_ntop(3): %m", __func__);
+               return false;
+       }
+       return true;
+}
+#endif /* !HAVE_GETNAMEINFO */
+
+/*
+ * Look up the hostname; report exceptional errors.  Caller must
+ * call freeaddrinfo(3) if a valid addrinfo is returned.
+ */
+__attribute_malloc__
+static struct addrinfo *
+get_addrinfo(const char *hostname, const struct addrinfo *hint)
+{
+       struct addrinfo *ai = NULL;
+       int error;
+
+       error = getaddrinfo(hostname, NULL, hint, &ai);
+       switch (error) {
+       case 0:
+               return ai;
+       case EAI_NONAME:
+               break;
+       default:
+               xlog(D_GENERAL, "%s: failed to resolve host %s: %s",
+                               __func__, hostname, gai_strerror(error));
+       }
+
+       return NULL;
+}
+
+#ifdef HAVE_GETNAMEINFO
+static _Bool
+get_nameinfo(const struct sockaddr *sap, const socklen_t salen,
+               /*@out@*/ char *buf, const socklen_t buflen)
+{
+       int error;
+
+       error = getnameinfo(sap, salen, buf, buflen, NULL, 0, NI_NAMEREQD);
+       if (error != 0) {
+               xlog(D_GENERAL, "%s: failed to resolve address: %s",
+                               __func__, gai_strerror(error));
+               return false;
+       }
+
+       return true;
+}
+#else  /* !HAVE_GETNAMEINFO */
+static _Bool
+get_nameinfo(const struct sockaddr *sap,
+               __attribute__ ((unused)) const socklen_t salen,
+               /*@out@*/ char *buf, socklen_t buflen)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)(char *)sap;
+       struct hostent *hp;
+
+       if (sin->sin_family != AF_INET) {
+               xlog(D_GENERAL, "%s: unknown address family: %d",
+                               sin->sin_family);
+               return false;
+       }
+
+       hp = gethostbyaddr((const char *)&(sin->sin_addr.s_addr),
+                               sizeof(struct in_addr), AF_INET);
+       if (hp == NULL) {
+               xlog(D_GENERAL, "%s: failed to resolve address: %m", __func__);
+               return false;
+       }
+
+       strncpy(buf, hp->h_name, (size_t)buflen);
+       return true;
+}
+#endif /* !HAVE_GETNAMEINFO */
+
+/**
+ * statd_canonical_name - choose file name for monitor record files
+ * @hostname: C string containing hostname or presentation address
+ *
+ * Returns a '\0'-terminated ASCII string containing a fully qualified
+ * canonical hostname, or NULL if @hostname does not have a reverse
+ * mapping.  Caller must free the result with free(3).
+ *
+ * Incoming hostnames are looked up to determine the canonical hostname,
+ * and incoming presentation addresses are converted to canonical
+ * hostnames.
+ *
+ * We won't monitor peers that don't have a reverse map.  The canonical
+ * name gives us a key for our monitor list.
+ */
+__attribute_malloc__
+char *
+statd_canonical_name(const char *hostname)
+{
+       struct addrinfo hint = {
+#ifdef IPV6_SUPPORTED
+               .ai_family      = AF_UNSPEC,
+#else  /* !IPV6_SUPPORTED */
+               .ai_family      = AF_INET,
+#endif /* !IPV6_SUPPORTED */
+               .ai_flags       = AI_NUMERICHOST,
+               .ai_protocol    = (int)IPPROTO_UDP,
+       };
+       char buf[NI_MAXHOST];
+       struct addrinfo *ai;
+
+       ai = get_addrinfo(hostname, &hint);
+       if (ai != NULL) {
+               /* @hostname was a presentation address */
+               _Bool result;
+               result = get_nameinfo(ai->ai_addr, ai->ai_addrlen,
+                                       buf, (socklen_t)sizeof(buf));
+               freeaddrinfo(ai);
+               if (!result)
+                       return NULL;
+               return strdup(buf);
+       }
+
+       /* @hostname was a hostname */
+       hint.ai_flags = AI_CANONNAME;
+       ai = get_addrinfo(hostname, &hint);
+       if (ai == NULL)
+               return NULL;
+       strcpy(buf, ai->ai_canonname);
+       freeaddrinfo(ai);
+
+       return strdup(buf);
+}
+
+/**
+ * statd_matchhostname - check if two hostnames are equivalent
+ * @hostname1: C string containing hostname
+ * @hostname2: C string containing hostname
+ *
+ * Returns true if the hostnames are the same, the hostnames resolve
+ * to the same canonical name, or the hostnames resolve to at least
+ * one address that is the same.  False is returned if the hostnames
+ * do not match in any of these ways, if either hostname contains
+ * wildcard characters, if either hostname is a netgroup name, or
+ * if an error occurs.
+ */
+_Bool
+statd_matchhostname(const char *hostname1, const char *hostname2)
+{
+       struct addrinfo *ai1, *ai2, *results1 = NULL, *results2 = NULL;
+       struct addrinfo hint = {
+               .ai_family      = AF_UNSPEC,
+               .ai_flags       = AI_CANONNAME,
+               .ai_protocol    = (int)IPPROTO_UDP,
+       };
+       _Bool result = false;
+
+       if (strcasecmp(hostname1, hostname2) == 0) {
+               result = true;
+               goto out;
+       }
+
+       results1 = get_addrinfo(hostname1, &hint);
+       if (results1 == NULL)
+               goto out;
+       results2 = get_addrinfo(hostname2, &hint);
+       if (results2 == NULL)
+               goto out;
+
+       if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
+               result = true;
+               goto out;
+       }
+
+       for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
+               for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
+                       if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
+                               result = true;
+                               break;
+                       }
+
+out:
+       freeaddrinfo(results2);
+       freeaddrinfo(results1);
+
+       xlog(D_CALL, "%s: hostnames %s", __func__,
+                       (result ? "matched" : "did not match"));
+       return result;
+}
diff --git a/utils/statd/log.c b/utils/statd/log.c
deleted file mode 100644 (file)
index a6ca996..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 1995 Olaf Kirch
- * Modified by Jeffrey A. Uphoff, 1995, 1997, 1999.
- * Modified by H.J. Lu, 1998.
- * Modified by Lon Hohberger, Oct. 2000
- *
- * NSM for Linux.
- */
-
-/* 
- *     log.c - logging functions for lockd/statd
- *     260295   okir   started with simply syslog logging.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <syslog.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <time.h>
-#include <sys/types.h>
-#include "log.h"
-#include "statd.h"
-
-static pid_t   mypid;
-                                                               /* Turns on logging to console/stderr. */
-#if 0
-static int     opt_debug = 0;  /* Will be command-line option, eventually */
-#endif
-
-void log_init(void)
-{
-       if (!(run_mode & MODE_LOG_STDERR)) 
-               openlog(name_p, LOG_PID | LOG_NDELAY, LOG_DAEMON);
-
-       mypid = getpid();
-
-       note(N_WARNING,"Version %s Starting",version_p);
-}
-
-void log_background(void)
-{
-       /* NOP */
-}
-
-void die(char *fmt, ...)
-{
-       char    buffer[1024];
-       va_list ap;
-
-       va_start(ap, fmt);
-       vsnprintf (buffer, 1024, fmt, ap);
-       va_end(ap);
-       buffer[1023]=0;
-
-       note(N_FATAL, "%s", buffer);
-
-#ifndef DEBUG
-       exit (2);
-#else
-       abort();        /* make a core */
-#endif
-}
-
-void note(int level, char *fmt, ...)
-{
-       char    buffer[1024];
-       va_list ap;
-
-       va_start(ap, fmt);
-       vsnprintf (buffer, 1024, fmt, ap);
-       va_end(ap);
-       buffer[1023]=0;
-
-       if ((!(run_mode & MODE_LOG_STDERR)) && (level < N_DEBUG)) {
-               syslog(level, "%s", buffer);
-       } else if (run_mode & MODE_LOG_STDERR) {
-               /* Log everything, including dprintf() stuff to stderr */
-               time_t          now;
-               struct tm *     tm;
-
-               time(&now);
-               tm = localtime(&now);
-               fprintf (stderr, "%02d/%02d/%04d %02d:%02d:%02d %s[%d]: %s\n",
-                       tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
-                       tm->tm_hour, tm->tm_min, tm->tm_sec,
-                       name_p, mypid,
-                       buffer);
-       }
-}
diff --git a/utils/statd/log.h b/utils/statd/log.h
deleted file mode 100644 (file)
index fc55d3c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 1995 Olaf Kirch
- * Modified by Jeffrey A. Uphoff, 1996, 1997, 1999.
- * Modified by Lon Hohberger, Oct. 2000
- *
- * NSM for Linux.
- */
-
-/*
- *     logging functionality
- *     260295  okir
- */
-
-#ifndef _LOCKD_LOG_H_
-#define _LOCKD_LOG_H_
-
-#include <syslog.h>
-
-void   log_init(void);
-void   log_background(void);
-void   log_enable(int facility);
-int    log_enabled(int facility);
-void   note(int level, char *fmt, ...);
-void   die(char *fmt, ...);
-
-/*
- * Map per-application severity to system severity. What's fatal for
- * lockd is merely an itching spot from the universe's point of view.
- */
-#define N_CRIT         LOG_CRIT
-#define N_FATAL                LOG_ERR
-#define N_ERROR                LOG_WARNING
-#define N_WARNING      LOG_NOTICE
-#define N_DEBUG                LOG_DEBUG
-
-#ifdef DEBUG
-#define dprintf                note
-#else
-#define dprintf                if (run_mode & MODE_LOG_STDERR) note
-#endif
-
-#endif /* _LOCKD_LOG_H_ */
index 725629116a2228be0fdb013c623e4f1426f31a6a..f2a086f33b2c1f9f90000d8231dbae2113b43785 100644 (file)
@@ -29,8 +29,7 @@ xmalloc (size_t size)
     return ((void *)NULL);
 
   if (!(ptr = malloc (size)))
-    /* SHIT!  SHIT!  SHIT! */
-    die ("malloc failed");
+    xlog_err ("malloc failed");
 
   return (ptr);
 }
@@ -46,32 +45,7 @@ xstrdup (const char *string)
 
   /* Will only fail if underlying malloc() fails (ENOMEM). */
   if (!(result = strdup (string)))
-    die ("strdup failed");
+    xlog_err ("strdup failed");
 
   return (result);
 }
-
-
-/*
- * Unlinking a file.
- */
-void
-xunlink (char *path, char *host)
-{
-       char *tozap;
-
-       tozap = malloc(strlen(path)+strlen(host)+2);
-       if (tozap == NULL) {
-               note(N_ERROR, "xunlink: malloc failed: errno %d (%s)", 
-                       errno, strerror(errno));
-               return;
-       }
-       sprintf (tozap, "%s/%s", path, host);
-
-       if (unlink (tozap) == -1)
-               note(N_ERROR, "unlink (%s): %s", tozap, strerror (errno));
-       else
-               dprintf (N_DEBUG, "Unlinked %s", tozap);
-
-       free(tozap);
-}
index a2c9e2b091c126d2d24b84a870f946f1f479ca68..325dfd3ac8bb3c12b7b6ab07b6b97923d46bd615 100644 (file)
 #include <arpa/inet.h>
 #include <dirent.h>
 
+#include "sockaddr.h"
 #include "rpcmisc.h"
-#include "misc.h"
+#include "nsm.h"
 #include "statd.h"
 #include "notlist.h"
 #include "ha-callout.h"
 
 notify_list *          rtnl = NULL;    /* Run-time notify list. */
 
-#define LINELEN (4*(8+1)+SM_PRIV_SIZE*2+1)
-
 /*
  * Reject requests from non-loopback addresses in order
  * to prevent attack described in CERT CA-99.05.
+ *
+ * Although the kernel contacts the statd service via only IPv4
+ * transports, the statd service can receive other requests, such
+ * as SM_NOTIFY, from remote peers via IPv6.
  */
-static int
+static _Bool
 caller_is_localhost(struct svc_req *rqstp)
 {
-       struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
-       struct in_addr  caller;
-
-       caller = sin->sin_addr;
-       if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
-               note(N_WARNING,
-                       "Call to statd from non-local host %s",
-                       inet_ntoa(caller));
-               return 0;
-       }
-       return 1;
+       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
+       char buf[INET6_ADDRSTRLEN];
+
+       if (!nfs_is_v4_loopback(sap))
+               goto out_nonlocal;
+       return true;
+
+out_nonlocal:
+       if (!statd_present_address(sap, buf, sizeof(buf)))
+               buf[0] = '\0';
+       xlog_warn("SM_MON/SM_UNMON call from non-local host %s", buf);
+       return false;
 }
 
 /*
@@ -61,13 +65,15 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
        char            *mon_name = argp->mon_id.mon_name,
                        *my_name  = argp->mon_id.my_id.my_name;
        struct my_id    *id = &argp->mon_id.my_id;
-       char            *path;
        char            *cp;
-       int             fd;
        notify_list     *clnt;
-       struct in_addr  my_addr;
-       char            *dnsname;
-       struct hostent  *hostinfo = NULL;
+       struct sockaddr_in my_addr = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
+       };
+       char *dnsname = NULL;
+
+       xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name);
 
        /* Assume that we'll fail. */
        result.res_stat = STAT_FAIL;
@@ -79,7 +85,6 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
         */
        if (!caller_is_localhost(rqstp))
                goto failure;
-       my_addr.s_addr = htonl(INADDR_LOOPBACK);
 
        /* 2.   Reject any registrations for non-lockd services.
         *
@@ -92,8 +97,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
        if (id->my_prog != 100021 ||
            (id->my_proc != 16 && id->my_proc != 24))
        {
-               note(N_WARNING,
-                       "Attempt to register callback to %d/%d",
+               xlog_warn("Attempt to register callback to %d/%d",
                        id->my_prog, id->my_proc);
                goto failure;
        }
@@ -105,12 +109,9 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
 
        /* must check for /'s in hostname!  See CERT's CA-96.09 for details. */
        if (strchr(mon_name, '/') || mon_name[0] == '.') {
-               note(N_CRIT, "SM_MON request for hostname containing '/' "
+               xlog(L_ERROR, "SM_MON request for hostname containing '/' "
                     "or starting '.': %s", mon_name);
-               note(N_CRIT, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
-               goto failure;
-       } else if ((hostinfo = gethostbyname(mon_name)) == NULL) {
-               note(N_WARNING, "gethostbyname error for %s", mon_name);
+               xlog(L_ERROR, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
                goto failure;
        }
 
@@ -124,15 +125,13 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
         * Now choose a hostname to use for matching.  We cannot
         * really trust much in the incoming NOTIFY, so to make
         * sure that multi-homed hosts work nicely, we get an
-        * FQDN now, and use that for matching
+        * FQDN now, and use that for matching.
         */
-       hostinfo = gethostbyaddr(hostinfo->h_addr,
-                                hostinfo->h_length,
-                                hostinfo->h_addrtype);
-       if (hostinfo)
-               dnsname = xstrdup(hostinfo->h_name);
-       else
-               dnsname = xstrdup(my_name);
+       dnsname = statd_canonical_name(mon_name);
+       if (dnsname == NULL) {
+               xlog(L_WARNING, "No canonical hostname found for %s", mon_name);
+               goto failure;
+       }
 
        /* Now check to see if this is a duplicate, and warn if so.
         * I will also return STAT_FAIL. (I *think* this is how I should
@@ -146,18 +145,19 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
        clnt = rtnl;
 
        while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
-               if (matchhostname(NL_MY_NAME(clnt), my_name) &&
+               if (statd_matchhostname(NL_MY_NAME(clnt), my_name) &&
                    NL_MY_PROC(clnt) == id->my_proc &&
                    NL_MY_PROG(clnt) == id->my_prog &&
                    NL_MY_VERS(clnt) == id->my_vers &&
                    memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) {
                        /* Hey!  We already know you guys! */
-                       dprintf(N_DEBUG,
+                       xlog(D_GENERAL,
                                "Duplicate SM_MON request for %s "
                                "from procedure on %s",
                                mon_name, my_name);
 
                        /* But we'll let you pass anyway. */
+                       free(dnsname);
                        goto success;
                }
                clnt = NL_NEXT(clnt);
@@ -168,11 +168,11 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
         * doesn't fail.  (I should probably fix this assumption.)
         */
        if (!(clnt = nlist_new(my_name, mon_name, 0))) {
-               note(N_WARNING, "out of memory");
+               free(dnsname);
+               xlog_warn("out of memory");
                goto failure;
        }
 
-       NL_ADDR(clnt) = my_addr;
        NL_MY_PROG(clnt) = id->my_prog;
        NL_MY_VERS(clnt) = id->my_vers;
        NL_MY_PROC(clnt) = id->my_proc;
@@ -182,40 +182,16 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
        /*
         * Now, Create file on stable storage for host.
         */
-
-       path=xmalloc(strlen(SM_DIR)+strlen(dnsname)+2);
-       sprintf(path, "%s/%s", SM_DIR, dnsname);
-       if ((fd = open(path, O_WRONLY|O_SYNC|O_CREAT|O_APPEND,
-                      S_IRUSR|S_IWUSR)) < 0) {
-               /* Didn't fly.  We won't monitor. */
-               note(N_ERROR, "creat(%s) failed: %s", path, strerror (errno));
+       if (!nsm_insert_monitored_host(dnsname,
+                               (struct sockaddr *)(char *)&my_addr, argp)) {
                nlist_free(NULL, clnt);
-               free(path);
                goto failure;
        }
-       {
-               char buf[LINELEN + 1 + SM_MAXSTRLEN*2 + 4];
-               char *e;
-               int i;
-               e = buf + sprintf(buf, "%08x %08x %08x %08x ",
-                                 my_addr.s_addr, id->my_prog,
-                                 id->my_vers, id->my_proc);
-               for (i=0; i<SM_PRIV_SIZE; i++)
-                       e += sprintf(e, "%02x", 0xff & (argp->priv[i]));
-               if (e+1-buf != LINELEN) abort();
-               e += sprintf(e, " %s %s\n", mon_name, my_name);
-               if (write(fd, buf, e-buf) != (e-buf)) {
-                       note(N_WARNING, "writing to %s failed: errno %d (%s)",
-                               path, errno, strerror(errno));
-               }
-       }
 
-       free(path);
        /* PRC: do the HA callout: */
        ha_callout("add-client", mon_name, my_name, -1);
        nlist_insert(&rtnl, clnt);
-       close(fd);
-       dprintf(N_DEBUG, "MONITORING %s for %s", mon_name, my_name);
+       xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name);
  success:
        result.res_stat = STAT_SUCC;
        /* SUN's sm_inter.x says this should be "state number of local site".
@@ -232,75 +208,49 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
        return (&result);
 
 failure:
-       note(N_WARNING, "STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
+       xlog_warn("STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
        return (&result);
 }
 
-void load_state(void)
+static unsigned int
+load_one_host(const char *hostname,
+               __attribute__ ((unused)) const struct sockaddr *sap,
+               const struct mon *m,
+               __attribute__ ((unused)) const time_t timestamp)
 {
-       DIR *d;
-       struct dirent *de;
-       char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
-
-       d = opendir(SM_DIR);
-       if (!d)
-               return;
-       while ((de = readdir(d))) {
-               char *path;
-               FILE *f;
-               int p;
-
-               if (de->d_name[0] == '.')
-                       continue;
-               path = xmalloc(strlen(SM_DIR)+strlen(de->d_name)+2);
-               sprintf(path, "%s/%s", SM_DIR, de->d_name);
-               f = fopen(path, "r");
-               free(path);
-               if (f == NULL)
-                       continue;
-               while (fgets(buf, sizeof(buf), f) != NULL) {
-                       int addr, proc, prog, vers;
-                       char priv[SM_PRIV_SIZE];
-                       char *monname, *myname;
-                       char *b;
-                       int i;
-                       notify_list     *clnt;
-
-                       buf[sizeof(buf)-1] = 0;
-                       b = strchr(buf, '\n');
-                       if (b) *b = 0;
-                       sscanf(buf, "%x %x %x %x ",
-                              &addr, &prog, &vers, &proc);
-                       b = buf+36;
-                       for (i=0; i<SM_PRIV_SIZE; i++) {
-                               sscanf(b, "%2x", &p);
-                               priv[i] = p;
-                               b += 2;
-                       }
-                       b++;
-                       monname = b;
-                       while (*b && *b != ' ') b++;
-                       if (*b) *b++ = '\0';
-                       while (*b == ' ') b++;
-                       myname = b;
-                       clnt = nlist_new(myname, monname, 0);
-                       if (!clnt)
-                               break;
-                       NL_ADDR(clnt).s_addr = addr;
-                       NL_MY_PROG(clnt) = prog;
-                       NL_MY_VERS(clnt) = vers;
-                       NL_MY_PROC(clnt) = proc;
-                       clnt->dns_name = xstrdup(de->d_name);
-                       memcpy(NL_PRIV(clnt), priv, SM_PRIV_SIZE);
-                       nlist_insert(&rtnl, clnt);
-               }
-               fclose(f);
+       notify_list *clnt;
+
+       clnt = nlist_new(m->mon_id.my_id.my_name,
+                               m->mon_id.mon_name, 0);
+       if (clnt == NULL)
+               return 0;
+
+       clnt->dns_name = strdup(hostname);
+       if (clnt->dns_name == NULL) {
+               nlist_free(NULL, clnt);
+               return 0;
        }
-       closedir(d);
-}
 
+       xlog(D_GENERAL, "Adding record for %s to the monitor list...",
+                       hostname);
 
+       NL_MY_PROG(clnt) = m->mon_id.my_id.my_prog;
+       NL_MY_VERS(clnt) = m->mon_id.my_id.my_vers;
+       NL_MY_PROC(clnt) = m->mon_id.my_id.my_proc;
+       memcpy(NL_PRIV(clnt), m->priv, SM_PRIV_SIZE);
 
+       nlist_insert(&rtnl, clnt);
+       return 1;
+}
+
+void load_state(void)
+{
+       unsigned int count;
+
+       count = nsm_load_monitor_list(load_one_host);
+       if (count)
+               xlog(D_GENERAL, "Loaded %u previously monitored hosts");
+}
 
 /*
  * Services SM_UNMON requests.
@@ -320,6 +270,8 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
        struct my_id    *id = &argp->my_id;
        char            *cp;
 
+       xlog(D_CALL, "Received SM_UNMON for %s from %s", mon_name, my_name);
+
        result.state = MY_STATE;
 
        if (!caller_is_localhost(rqstp))
@@ -333,9 +285,8 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
 
        /* Check if we're monitoring anyone. */
        if (rtnl == NULL) {
-               note(N_WARNING,
-                       "Received SM_UNMON request from %s for %s while not "
-                       "monitoring any hosts.", my_name, argp->mon_name);
+               xlog_warn("Received SM_UNMON request from %s for %s while not "
+                       "monitoring any hosts", my_name, argp->mon_name);
                return (&result);
        }
        clnt = rtnl;
@@ -347,18 +298,19 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
         * entry winds up in the list the way I'm currently handling them.)
         */
        while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
-               if (matchhostname(NL_MY_NAME(clnt), my_name) &&
+               if (statd_matchhostname(NL_MY_NAME(clnt), my_name) &&
                        NL_MY_PROC(clnt) == id->my_proc &&
                        NL_MY_PROG(clnt) == id->my_prog &&
                        NL_MY_VERS(clnt) == id->my_vers) {
                        /* Match! */
-                       dprintf(N_DEBUG, "UNMONITORING %s for %s",
+                       xlog(D_GENERAL, "UNMONITORING %s for %s",
                                        mon_name, my_name);
 
                        /* PRC: do the HA callout: */
                        ha_callout("del-client", mon_name, my_name, -1);
 
-                       xunlink(SM_DIR, clnt->dns_name);
+                       nsm_delete_monitored_host(clnt->dns_name,
+                                                       mon_name, my_name);
                        nlist_free(&rtnl, clnt);
 
                        return (&result);
@@ -367,7 +319,7 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
        }
 
  failure:
-       note(N_WARNING, "Received erroneous SM_UNMON request from %s for %s",
+       xlog_warn("Received erroneous SM_UNMON request from %s for %s",
                my_name, mon_name);
        return (&result);
 }
@@ -381,13 +333,15 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
        notify_list     *clnt;
        char            *my_name = argp->my_name;
 
+       xlog(D_CALL, "Received SM_UNMON_ALL for %s", my_name);
+
        if (!caller_is_localhost(rqstp))
                goto failure;
 
        result.state = MY_STATE;
 
        if (rtnl == NULL) {
-               note(N_WARNING, "Received SM_UNMON_ALL request from %s "
+               xlog_warn("Received SM_UNMON_ALL request from %s "
                        "while not monitoring any hosts", my_name);
                return (&result);
        }
@@ -401,7 +355,7 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
                        char            mon_name[SM_MAXSTRLEN + 1];
                        notify_list     *temp;
 
-                       dprintf(N_DEBUG,
+                       xlog(D_GENERAL,
                                "UNMONITORING (SM_UNMON_ALL) %s for %s",
                                NL_MON_NAME(clnt), NL_MY_NAME(clnt));
                        strncpy(mon_name, NL_MON_NAME(clnt),
@@ -410,7 +364,8 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
                        temp = NL_NEXT(clnt);
                        /* PRC: do the HA callout: */
                        ha_callout("del-client", mon_name, my_name, -1);
-                       xunlink(SM_DIR, clnt->dns_name);
+                       nsm_delete_monitored_host(clnt->dns_name,
+                                                       mon_name, my_name);
                        nlist_free(&rtnl, clnt);
                        ++count;
                        clnt = temp;
@@ -419,8 +374,8 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
        }
 
        if (!count) {
-               dprintf(N_DEBUG, "SM_UNMON_ALL request from %s with no "
-                       "SM_MON requests from it.", my_name);
+               xlog(D_GENERAL, "SM_UNMON_ALL request from %s with no "
+                       "SM_MON requests from it", my_name);
        }
 
  failure:
index 1698c26abef92166941dc39eba066b879422957c..0341c159167836661e2d3027279bc7e3a4a86dba 100644 (file)
@@ -17,7 +17,6 @@
 #endif
 
 #include <string.h>
-#include "misc.h"
 #include "statd.h"
 #include "notlist.h"
 
@@ -190,7 +189,6 @@ nlist_clone(notify_list *entry)
        NL_MY_PROG(new) = NL_MY_PROG(entry);
        NL_MY_VERS(new) = NL_MY_VERS(entry);
        NL_MY_PROC(new) = NL_MY_PROC(entry);
-       NL_ADDR(new)    = NL_ADDR(entry);
        memcpy(NL_PRIV(new), NL_PRIV(entry), SM_PRIV_SIZE);
 
        return new;
@@ -234,7 +232,8 @@ nlist_gethost(notify_list *list, char *host, int myname)
        notify_list     *lp;
 
        for (lp = list; lp; lp = lp->next) {
-               if (matchhostname(host, myname? NL_MY_NAME(lp) : NL_MON_NAME(lp)))
+               if (statd_matchhostname(host,
+                               myname? NL_MY_NAME(lp) : NL_MON_NAME(lp)))
                        return lp;
        }
 
index 664c9d881bc84021b123ed75f3ed8463f08627ea..6ed0da80cdca1e72d01d380c8b8b83acf05acb90 100644 (file)
  */
 struct notify_list {
   mon                  mon;    /* Big honkin' NSM structure. */
-  struct in_addr       addr;   /* IP address for callback. */
-  unsigned short       port;   /* port number for callback */
+  in_port_t            port;   /* port number for callback */
   short int            times;  /* Counter used for various things. */
   int                  state;  /* For storing notified state for callbacks. */
   char                 *dns_name; /* used for matching incoming
                                    * NOTIFY requests */
   struct notify_list   *next;  /* Linked list forward pointer. */
   struct notify_list   *prev;  /* Linked list backward pointer. */
-  u_int32_t            xid;    /* XID of MS_NOTIFY RPC call */
+  uint32_t             xid;    /* XID of MS_NOTIFY RPC call */
   time_t               when;   /* notify: timeout for re-xmit */
 };
 
@@ -53,7 +52,6 @@ extern notify_list *  nlist_gethost(notify_list *, char *, int);
 #define NL_FIRST       NL_NEXT
 #define NL_PREV(L)     ((L)->prev)
 #define NL_DATA(L)     ((L)->mon)
-#define NL_ADDR(L)     ((L)->addr)
 #define NL_STATE(L)    ((L)->state)
 #define NL_TIMES(L)    ((L)->times)
 #define NL_MON_ID(L)   (NL_DATA((L)).mon_id)
index cc1a4a46dfc12301642ec64af7be11ed7173b03c..0e52fe2b81b1f357637b0e824fe1d4da0cc3827f 100644 (file)
 #include <netdb.h>
 #include <string.h>
 #include <unistd.h>
-#ifdef HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#endif /* HAVE_IFADDRS_H */
+
 #include "sm_inter.h"
 #include "statd.h"
 #include "notlist.h"
-#include "log.h"
 #include "ha-callout.h"
 
+#include "nsm.h"
+#include "nfsrpc.h"
+
 #if SIZEOF_SOCKLEN_T - 0 == 0
 #define socklen_t int
 #endif
 
-#define MAXMSGSIZE     (2048 / sizeof(unsigned int))
-
-static unsigned long   xid = 0;        /* RPC XID counter */
 static int             sockfd = -1;    /* notify socket */
 
 /*
@@ -81,7 +78,7 @@ statd_get_socket(void)
                if (sockfd >= 0) close(sockfd);
 
                if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-                       note(N_CRIT, "%s: Can't create socket: %m", __func__);
+                       xlog(L_ERROR, "%s: Can't create socket: %m", __func__);
                        return -1;
                }
 
@@ -91,7 +88,7 @@ statd_get_socket(void)
                sin.sin_addr.s_addr = INADDR_ANY;
 
                if (bindresvport(sockfd, &sin) < 0) {
-                       dprintf(N_WARNING, "%s: can't bind to reserved port",
+                       xlog(D_GENERAL, "%s: can't bind to reserved port",
                                        __func__);
                        break;
                }
@@ -104,112 +101,37 @@ statd_get_socket(void)
        return sockfd;
 }
 
-static unsigned long
-xmit_call(struct sockaddr_in *sin,
-         u_int32_t prog, u_int32_t vers, u_int32_t proc,
-         xdrproc_t func, void *obj)
-/*             __u32 prog, __u32 vers, __u32 proc, xdrproc_t func, void *obj) */
-{
-       unsigned int            msgbuf[MAXMSGSIZE], msglen;
-       struct rpc_msg          mesg;
-       struct pmap             pmap;
-       XDR                     xdr, *xdrs = &xdr;
-       int                     err;
-
-       if (!xid)
-               xid = getpid() + time(NULL);
-
-       mesg.rm_xid = ++xid;
-       mesg.rm_direction = CALL;
-       mesg.rm_call.cb_rpcvers = 2;
-       if (sin->sin_port == 0) {
-               sin->sin_port = htons(PMAPPORT);
-               mesg.rm_call.cb_prog = PMAPPROG;
-               mesg.rm_call.cb_vers = PMAPVERS;
-               mesg.rm_call.cb_proc = PMAPPROC_GETPORT;
-               pmap.pm_prog = prog;
-               pmap.pm_vers = vers;
-               pmap.pm_prot = IPPROTO_UDP;
-               pmap.pm_port = 0;
-               func = (xdrproc_t) xdr_pmap;
-               obj  = &pmap;
-       } else {
-               mesg.rm_call.cb_prog = prog;
-               mesg.rm_call.cb_vers = vers;
-               mesg.rm_call.cb_proc = proc;
-       }
-       mesg.rm_call.cb_cred.oa_flavor = AUTH_NULL;
-       mesg.rm_call.cb_cred.oa_base = (caddr_t) NULL;
-       mesg.rm_call.cb_cred.oa_length = 0;
-       mesg.rm_call.cb_verf.oa_flavor = AUTH_NULL;
-       mesg.rm_call.cb_verf.oa_base = (caddr_t) NULL;
-       mesg.rm_call.cb_verf.oa_length = 0;
-
-       /* Create XDR memory object for encoding */
-       xdrmem_create(xdrs, (caddr_t) msgbuf, sizeof(msgbuf), XDR_ENCODE);
-
-       /* Encode the RPC header part and payload */
-       if (!xdr_callmsg(xdrs, &mesg) || !func(xdrs, obj)) {
-               dprintf(N_WARNING, "%s: can't encode RPC message!", __func__);
-               xdr_destroy(xdrs);
-               return 0;
-       }
-
-       /* Get overall length of datagram */
-       msglen = xdr_getpos(xdrs);
-
-       if ((err = sendto(sockfd, msgbuf, msglen, 0,
-                       (struct sockaddr *) sin, sizeof(*sin))) < 0) {
-               dprintf(N_WARNING, "%s: sendto failed: %m", __func__);
-       } else if (err != msglen) {
-               dprintf(N_WARNING, "%s: short write: %m", __func__);
-       }
-
-       xdr_destroy(xdrs);
-
-       return err == msglen? xid : 0;
-}
-
 static notify_list *
-recv_rply(struct sockaddr_in *sin, u_long *portp)
+recv_rply(u_long *portp)
 {
-       unsigned int            msgbuf[MAXMSGSIZE], msglen;
-       struct rpc_msg          mesg;
+       char                    msgbuf[NSM_MAXMSGSIZE];
+       ssize_t                 msglen;
        notify_list             *lp = NULL;
-       XDR                     xdr, *xdrs = &xdr;
-       socklen_t               alen = sizeof(*sin);
-
-       /* Receive message */
-       if ((msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
-                       (struct sockaddr *) sin, &alen)) < 0) {
-               dprintf(N_WARNING, "%s: recvfrom failed: %m", __func__);
+       XDR                     xdr;
+       struct sockaddr_in      sin;
+       socklen_t               alen = (socklen_t)sizeof(sin);
+       uint32_t                xid;
+
+       memset(msgbuf, 0, sizeof(msgbuf));
+       msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
+                               (struct sockaddr *)(char *)&sin, &alen);
+       if (msglen == (ssize_t)-1) {
+               xlog_warn("%s: recvfrom failed: %m", __func__);
                return NULL;
        }
 
-       /* Create XDR object for decoding buffer */
-       xdrmem_create(xdrs, (caddr_t) msgbuf, msglen, XDR_DECODE);
-
-       memset(&mesg, 0, sizeof(mesg));
-       mesg.rm_reply.rp_acpt.ar_results.where = NULL;
-       mesg.rm_reply.rp_acpt.ar_results.proc = (xdrproc_t) xdr_void;
-
-       if (!xdr_replymsg(xdrs, &mesg)) {
-               note(N_WARNING, "%s: can't decode RPC message!", __func__);
+       memset(&xdr, 0, sizeof(xdr));
+       xdrmem_create(&xdr, msgbuf, (unsigned int)msglen, XDR_DECODE);
+       xid = nsm_parse_reply(&xdr);
+       if (xid == 0)
                goto done;
-       }
+       if (sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
+               struct in_addr addr = sin.sin_addr;
+               char buf[INET_ADDRSTRLEN];
 
-       if (mesg.rm_reply.rp_stat != 0) {
-               note(N_WARNING, "%s: [%s] RPC status %d", 
-                               __func__,
-                               inet_ntoa(sin->sin_addr),
-                               mesg.rm_reply.rp_stat);
-               goto done;
-       }
-       if (mesg.rm_reply.rp_acpt.ar_stat != 0) {
-               note(N_WARNING, "%s: [%s] RPC status %d",
-                               __func__,
-                               inet_ntoa(sin->sin_addr),
-                               mesg.rm_reply.rp_acpt.ar_stat);
+               xlog_warn("%s: Unrecognized reply from %s", __func__,
+                               inet_ntop(AF_INET, &addr, buf,
+                                               (socklen_t)sizeof(buf)));
                goto done;
        }
 
@@ -217,32 +139,15 @@ recv_rply(struct sockaddr_in *sin, u_long *portp)
                /* LH - this was a bug... it should have been checking
                 * the xid from the response message from the client,
                 * not the static, internal xid */
-               if (lp->xid != mesg.rm_xid)
+               if (lp->xid != xid)
                        continue;
-               if (lp->addr.s_addr != sin->sin_addr.s_addr) {
-                       char addr [18];
-                       strncpy (addr, inet_ntoa(lp->addr),
-                                sizeof (addr) - 1);
-                       addr [sizeof (addr) - 1] = '\0';
-                       dprintf(N_WARNING, "%s: address mismatch: "
-                               "expected %s, got %s", __func__,
-                               addr, inet_ntoa(sin->sin_addr));
-               }
-               if (lp->port == 0) {
-                       if (!xdr_u_long(xdrs, portp)) {
-                               note(N_WARNING,
-                                       "%s: [%s] can't decode reply body!",
-                                       __func__,
-                                       inet_ntoa(sin->sin_addr));
-                               lp = NULL;
-                               goto done;
-                       }
-               }
+               if (lp->port == 0)
+                       *portp = nsm_recv_getport(&xdr);
                break;
        }
 
 done:
-       xdr_destroy(xdrs);
+       xdr_destroy(&xdr);
        return lp;
 }
 
@@ -253,15 +158,10 @@ static int
 process_entry(notify_list *lp)
 {
        struct sockaddr_in      sin;
-       struct status           new_status;
-       xdrproc_t               func;
-       void                    *objp;
-       u_int32_t               proc, vers, prog;
-/*     __u32                   proc, vers, prog; */
 
        if (NL_TIMES(lp) == 0) {
-               note(N_DEBUG, "%s: Cannot notify %s, giving up.",
-                               __func__, inet_ntoa(NL_ADDR(lp)));
+               xlog(D_GENERAL, "%s: Cannot notify localhost, giving up",
+                               __func__);
                return 0;
        }
 
@@ -270,23 +170,31 @@ process_entry(notify_list *lp)
        sin.sin_port   = lp->port;
        /* LH - moved address into switch */
 
-       prog = NL_MY_PROG(lp);
-       vers = NL_MY_VERS(lp);
-       proc = NL_MY_PROC(lp);
-
        /* __FORCE__ loopback for callbacks to lockd ... */
        /* Just in case we somehow ignored it thus far */
        sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
-       func = (xdrproc_t) xdr_status;
-       objp = &new_status;
-       new_status.mon_name = NL_MON_NAME(lp);
-       new_status.state    = NL_STATE(lp);
-       memcpy(new_status.priv, NL_PRIV(lp), SM_PRIV_SIZE);
+       if (sin.sin_port == 0)
+               lp->xid = nsm_xmit_getport(sockfd, &sin,
+                                       (rpcprog_t)NL_MY_PROG(lp),
+                                       (rpcvers_t)NL_MY_VERS(lp));
+       else {
+               struct mon m;
+
+               memcpy(m.priv, NL_PRIV(lp), SM_PRIV_SIZE);
 
-       lp->xid = xmit_call(&sin, prog, vers, proc, func, objp);
-       if (!lp->xid) {
-               note(N_WARNING, "%s: failed to notify port %d",
+               m.mon_id.mon_name = NL_MON_NAME(lp);
+               m.mon_id.my_id.my_name = NULL;
+               m.mon_id.my_id.my_prog = NL_MY_PROG(lp);
+               m.mon_id.my_id.my_vers = NL_MY_VERS(lp);
+               m.mon_id.my_id.my_proc = NL_MY_PROC(lp);
+
+               lp->xid = nsm_xmit_nlmcall(sockfd,
+                               (struct sockaddr *)(char *)&sin,
+                               (socklen_t)sizeof(sin), &m, NL_STATE(lp));
+       }
+       if (lp->xid == 0) {
+               xlog_warn("%s: failed to notify port %d",
                                __func__, ntohs(lp->port));
        }
        NL_TIMES(lp) -= 1;
@@ -300,14 +208,13 @@ process_entry(notify_list *lp)
 int
 process_reply(FD_SET_TYPE *rfds)
 {
-       struct sockaddr_in      sin;
        notify_list             *lp;
        u_long                  port;
 
        if (sockfd == -1 || !FD_ISSET(sockfd, rfds))
                return 0;
 
-       if (!(lp = recv_rply(&sin, &port)))
+       if (!(lp = recv_rply(&port)))
                return 1;
 
        if (lp->port == 0) {
@@ -319,10 +226,10 @@ process_reply(FD_SET_TYPE *rfds)
                        nlist_insert_timer(&notify, lp);
                        return 1;
                }
-               note(N_WARNING, "%s: [%s] service %d not registered",
-                       __func__, inet_ntoa(lp->addr), NL_MY_PROG(lp));
+               xlog_warn("%s: service %d not registered on localhost",
+                       __func__, NL_MY_PROG(lp));
        } else {
-               dprintf(N_DEBUG, "%s: Callback to %s (for %d) succeeded.",
+               xlog(D_GENERAL, "%s: Callback to %s (for %d) succeeded",
                        __func__, NL_MY_NAME(lp), NL_MON_NAME(lp));
        }
        nlist_free(&notify, lp);
@@ -346,8 +253,8 @@ process_notify_list(void)
                        nlist_remove(&notify, entry);
                        nlist_insert_timer(&notify, entry);
                } else {
-                       note(N_ERROR,
-                               "%s: Can't callback %s (%d,%d), giving up.",
+                       xlog(L_ERROR,
+                               "%s: Can't callback %s (%d,%d), giving up",
                                        __func__,
                                        NL_MY_NAME(entry),
                                        NL_MY_PROG(entry),
index a7ecb85c275509e687c4351955c4c5b4d1e3c03d..f1d0bf886f3dfb5caf87ebdeb38406a75db4b329 100644 (file)
@@ -8,8 +8,10 @@
 #include <config.h>
 #endif
 
+#include <netdb.h>
 #include <arpa/inet.h>
 
+#include "sockaddr.h"
 #include "rpcmisc.h"
 #include "statd.h"
 #include "notlist.h"
@@ -19,32 +21,28 @@ extern void my_svc_exit (void);
 
 /*
  * Services SM_SIMU_CRASH requests.
+ *
+ * Although the kernel contacts the statd service via only IPv4
+ * transports, the statd service can receive other requests, such
+ * as SM_NOTIFY, from remote peers via IPv6.
  */
 void *
-sm_simu_crash_1_svc (void *argp, struct svc_req *rqstp)
+sm_simu_crash_1_svc (__attribute__ ((unused)) void *argp, struct svc_req *rqstp)
 {
-  struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
+  struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
+  char buf[INET6_ADDRSTRLEN];
   static char *result = NULL;
-  struct in_addr caller;
 
-  if (sin->sin_family != AF_INET) {
-    note(N_WARNING, "Call to statd from non-AF_INET address");
-    goto failure;
-  }
+  xlog(D_CALL, "Received SM_SIMU_CRASH");
 
-  caller = sin->sin_addr;
-  if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
-    note(N_WARNING, "Call to statd from non-local host %s",
-      inet_ntoa(caller));
-    goto failure;
-  }
+  if (!nfs_is_v4_loopback(sap))
+    goto out_nonlocal;
 
-  if (ntohs(sin->sin_port) >= 1024) {
-    note(N_WARNING, "Call to statd-simu-crash from unprivileged port");
+  if ((int)nfs_get_port(sap) >= IPPORT_RESERVED) {
+    xlog_warn("SM_SIMU_CRASH call from unprivileged port");
     goto failure;
   }
 
-  note (N_WARNING, "*** SIMULATING CRASH! ***");
   my_svc_exit ();
 
   if (rtnl)
@@ -52,4 +50,10 @@ sm_simu_crash_1_svc (void *argp, struct svc_req *rqstp)
 
  failure:
   return ((void *)&result);
+
+ out_nonlocal:
+  if (!statd_present_address(sap, buf, sizeof(buf)))
+    buf[0] = '\0';
+  xlog_warn("SM_SIMU_CRASH call from non-local host %s", buf);
+  goto failure;
 }
index de8f1c947e0ef0e0238503479e493d10f3061efd..4ed1468ecf31022af4ca6a21c8a9f4a2c5cd4698 100644 (file)
@@ -38,7 +38,9 @@ extern void svc_exit (void);
 void
 simulator (int argc, char **argv)
 {
-  log_enable (1);
+  xlog_stderr (1);
+  xlog_syslog (0);
+  xlog_open ("statd simulator");
 
   if (argc == 2)
     if (!strcasecmp (*argv, "crash"))
@@ -61,7 +63,7 @@ simulator (int argc, char **argv)
       simulate_mon (*(&argv[1]), *(&argv[2]), *(&argv[3]), *(&argv[4]),
                    *(&argv[5]));
   }
-  die ("WTF?  Give me something I can use!");
+  xlog_err ("WTF?  Give me something I can use!");
 }
 
 static void
@@ -72,11 +74,11 @@ simulate_mon (char *calling, char *monitoring, char *as, char *proggy,
   sm_stat_res *result;
   mon mon;
 
-  dprintf (N_DEBUG, "Calling %s (as %s) to monitor %s", calling, as,
+  xlog (D_GENERAL, "Calling %s (as %s) to monitor %s", calling, as,
           monitoring);
 
   if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
-    die ("%s", clnt_spcreateerror ("clnt_create"));
+    xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
 
   memcpy (mon.priv, fool, SM_PRIV_SIZE);
   mon.mon_id.my_id.my_name = xstrdup (as);
@@ -87,16 +89,15 @@ simulate_mon (char *calling, char *monitoring, char *as, char *proggy,
   mon.mon_id.mon_name = monitoring;
 
   if (!(result = sm_mon_1 (&mon, client)))
-    die ("%s", clnt_sperror (client, "sm_mon_1"));
+    xlog_err ("%s", clnt_sperror (client, "sm_mon_1"));
 
   free (mon.mon_id.my_id.my_name);
 
   if (result->res_stat != STAT_SUCC) {
-    note (N_FATAL, "SM_MON request failed, state: %d", result->state);
-    exit (0);
+    xlog_err ("SM_MON request failed, state: %d", result->state);
   } else {
-    dprintf (N_DEBUG, "SM_MON result successful, state: %d\n", result->state);
-    dprintf (N_DEBUG, "Waiting for callback.");
+    xlog (D_GENERAL, "SM_MON result successful, state: %d\n", result->state);
+    xlog (D_GENERAL, "Waiting for callback");
     daemon_simulator ();
     exit (0);
   }
@@ -109,11 +110,11 @@ simulate_unmon (char *calling, char *unmonitoring, char *as, char *proggy)
   sm_stat *result;
   mon_id mon_id;
 
-  dprintf (N_DEBUG, "Calling %s (as %s) to unmonitor %s", calling, as,
+  xlog (D_GENERAL, "Calling %s (as %s) to unmonitor %s", calling, as,
           unmonitoring);
 
   if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
-    die ("%s", clnt_spcreateerror ("clnt_create"));
+    xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
 
   mon_id.my_id.my_name = xstrdup (as);
   mon_id.my_id.my_prog = atoi (proggy) * SIM_SM_PROG;
@@ -122,10 +123,10 @@ simulate_unmon (char *calling, char *unmonitoring, char *as, char *proggy)
   mon_id.mon_name = unmonitoring;
 
   if (!(result = sm_unmon_1 (&mon_id, client)))
-    die ("%s", clnt_sperror (client, "sm_unmon_1"));
+    xlog_err ("%s", clnt_sperror (client, "sm_unmon_1"));
 
   free (mon_id.my_id.my_name);
-  dprintf (N_DEBUG, "SM_UNMON request returned state: %d\n", result->state);
+  xlog (D_GENERAL, "SM_UNMON request returned state: %d\n", result->state);
   exit (0);
 }
 
@@ -136,10 +137,10 @@ simulate_unmon_all (char *calling, char *as, char *proggy)
   sm_stat *result;
   my_id my_id;
 
-  dprintf (N_DEBUG, "Calling %s (as %s) to unmonitor all hosts", calling, as);
+  xlog (D_GENERAL, "Calling %s (as %s) to unmonitor all hosts", calling, as);
 
   if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
-    die ("%s", clnt_spcreateerror ("clnt_create"));
+    xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
 
   my_id.my_name = xstrdup (as);
   my_id.my_prog = atoi (proggy) * SIM_SM_PROG;
@@ -147,10 +148,10 @@ simulate_unmon_all (char *calling, char *as, char *proggy)
   my_id.my_proc = SIM_SM_MON;
 
   if (!(result = sm_unmon_all_1 (&my_id, client)))
-    die ("%s", clnt_sperror (client, "sm_unmon_all_1"));
+    xlog_err ("%s", clnt_sperror (client, "sm_unmon_all_1"));
 
   free (my_id.my_name);
-  dprintf (N_DEBUG, "SM_UNMON_ALL request returned state: %d\n", result->state);
+  xlog (D_GENERAL, "SM_UNMON_ALL request returned state: %d\n", result->state);
   exit (0);
 }
 
@@ -160,10 +161,10 @@ simulate_crash (char *host)
   CLIENT *client;
 
   if ((client = clnt_create (host, SM_PROG, SM_VERS, "udp")) == NULL)
-    die ("%s", clnt_spcreateerror ("clnt_create"));
+    xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
 
   if (!sm_simu_crash_1 (NULL, client))
-    die ("%s", clnt_sperror (client, "sm_simu_crash_1"));
+    xlog_err ("%s", clnt_sperror (client, "sm_simu_crash_1"));
 
   exit (0);
 }
@@ -176,18 +177,18 @@ simulate_stat (char *calling, char *monitoring)
   sm_stat_res *result;
   
   if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
-    die ("%s", clnt_spcreateerror ("clnt_create"));
+    xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
 
   checking.mon_name = monitoring;
 
   if (!(result = sm_stat_1 (&checking, client)))
-    die ("%s", clnt_sperror (client, "sm_stat_1"));
+    xlog_err ("%s", clnt_sperror (client, "sm_stat_1"));
 
   if (result->res_stat == STAT_SUCC)
-    dprintf (N_DEBUG, "STAT_SUCC from %s for %s, state: %d", calling,
+    xlog (D_GENERAL, "STAT_SUCC from %s for %s, state: %d", calling,
             monitoring, result->state);
   else
-    dprintf (N_DEBUG, "STAT_FAIL from %s for %s, state: %d", calling,
+    xlog (D_GENERAL, "STAT_FAIL from %s for %s, state: %d", calling,
             monitoring, result->state);
 
   exit (0);
@@ -196,9 +197,8 @@ simulate_stat (char *calling, char *monitoring)
 static void
 sim_killer (int sig)
 {
-  note (N_FATAL, "Simulator caught signal %d, un-registering and exiting.", sig);
   pmap_unset (sim_port, SIM_SM_VERS);
-  exit (0);
+  xlog_err ("Simulator caught signal %d, un-registering and exiting", sig);
 }
 
 static void
@@ -219,7 +219,7 @@ sim_sm_mon_1_svc (struct status *argp, struct svc_req *rqstp)
 {
   static char *result;
 
-  dprintf (N_DEBUG, "Recieved state %d for mon_name %s (opaque \"%s\")",
+  xlog (D_GENERAL, "Recieved state %d for mon_name %s (opaque \"%s\")",
           argp->state, argp->mon_name, argp->priv);
   svc_exit ();
   return ((void *)&result);
index 72dcff436fd7f0d9a193dcba1198d1c3e8bfd10d..3259a3e973d774de310f93065fcc1c867a026124 100644 (file)
@@ -8,6 +8,7 @@
 #include <config.h>
 #endif
 
+#include <err.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <grp.h>
 
-#ifndef BASEDIR
-# ifdef NFS_STATEDIR
-#  define BASEDIR              NFS_STATEDIR
-# else
-#  define BASEDIR              "/var/lib/nfs"
-# endif
-#endif
-
-#define DEFAULT_SM_STATE_PATH  BASEDIR "/state"
-#define        DEFAULT_SM_DIR_PATH     BASEDIR "/sm"
-#define        DEFAULT_SM_BAK_PATH     DEFAULT_SM_DIR_PATH ".bak"
+#include "sockaddr.h"
+#include "xlog.h"
+#include "nsm.h"
+#include "nfsrpc.h"
 
-char *_SM_BASE_PATH = BASEDIR;
-char *_SM_STATE_PATH = DEFAULT_SM_STATE_PATH;
-char *_SM_DIR_PATH = DEFAULT_SM_DIR_PATH;
-char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH;
+#ifndef HAVE_DECL_AI_ADDRCONFIG
+#define AI_ADDRCONFIG  0
+#endif
 
-#define NSM_PROG       100024
-#define NSM_PROGRAM    100024
-#define NSM_VERSION    1
 #define NSM_TIMEOUT    2
-#define NSM_NOTIFY     6
 #define NSM_MAX_TIMEOUT        120     /* don't make this too big */
-#define MAXMSGSIZE     256
 
 struct nsm_host {
        struct nsm_host *       next;
        char *                  name;
-       char *                  path;
-       struct sockaddr_storage addr;
+       char *                  mon_name;
+       char *                  my_name;
        struct addrinfo         *ai;
        time_t                  last_used;
        time_t                  send_next;
        unsigned int            timeout;
        unsigned int            retries;
-       unsigned int            xid;
+       uint32_t                xid;
 };
 
 static char            nsm_hostname[256];
-static uint32_t                nsm_state;
+static int             nsm_state;
+static int             nsm_family = AF_INET;
 static int             opt_debug = 0;
-static int             opt_quiet = 0;
-static int             opt_update_state = 1;
+static _Bool           opt_update_state = true;
 static unsigned int    opt_max_retry = 15 * 60;
-static char *          opt_srcaddr = 0;
-static uint16_t                opt_srcport = 0;
-static int             log_syslog = 0;
+static char *          opt_srcaddr = NULL;
+static char *          opt_srcport = NULL;
 
-static unsigned int    nsm_get_state(int);
-static void            notify(void);
+static void            notify(const int sock);
 static int             notify_host(int, struct nsm_host *);
 static void            recv_reply(int);
-static void            backup_hosts(const char *, const char *);
-static void            get_hosts(const char *);
 static void            insert_host(struct nsm_host *);
 static struct nsm_host *find_host(uint32_t);
-static void            nsm_log(int fac, const char *fmt, ...);
 static int             record_pid(void);
-static void            drop_privs(void);
-static void            set_kernel_nsm_state(int state);
 
 static struct nsm_host *       hosts = NULL;
 
-/*
- * Address handling utilities
- */
-
-static unsigned short smn_get_port(const struct sockaddr *sap)
+__attribute_malloc__
+static struct addrinfo *
+smn_lookup(const char *name)
 {
-       switch (sap->sa_family) {
-       case AF_INET:
-               return ntohs(((struct sockaddr_in *)sap)->sin_port);
-       case AF_INET6:
-               return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
-       }
-       return 0;
-}
+       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,
+       };
+       int error;
 
-static void smn_set_port(struct sockaddr *sap, const unsigned short port)
-{
-       switch (sap->sa_family) {
-       case AF_INET:
-               ((struct sockaddr_in *)sap)->sin_port = htons(port);
-               break;
-       case AF_INET6:
-               ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
-               break;
+       error = getaddrinfo(name, NULL, &hint, &ai);
+       if (error != 0) {
+               xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error));
+               return NULL;
        }
+
+       return ai;
 }
 
-static struct addrinfo *smn_lookup(const char *name)
+__attribute_malloc__
+static struct nsm_host *
+smn_alloc_host(const char *hostname, const char *mon_name,
+               const char *my_name, const time_t timestamp)
 {
-       struct addrinfo *ai, hint = {
-#if HAVE_DECL_AI_ADDRCONFIG
-               .ai_flags       = AI_ADDRCONFIG,
-#endif /* HAVE_DECL_AI_ADDRCONFIG */
-               .ai_family      = AF_INET,
-               .ai_protocol    = IPPROTO_UDP,
-       };
-       int error;
+       struct nsm_host *host;
 
-       error = getaddrinfo(name, NULL, &hint, &ai);
-       switch (error) {
-       case 0:
-               return ai;
-       case EAI_SYSTEM: 
-               if (opt_debug)
-                       nsm_log(LOG_ERR, "getaddrinfo(3): %s",
-                                       strerror(errno));
-               break;
-       default:
-               if (opt_debug)
-                       nsm_log(LOG_ERR, "getaddrinfo(3): %s",
-                                       gai_strerror(error));
+       host = calloc(1, sizeof(*host));
+       if (host == NULL)
+               goto out_nomem;
+
+       host->name = strdup(hostname);
+       host->mon_name = strdup(mon_name);
+       host->my_name = strdup(my_name);
+       if (host->name == NULL ||
+           host->mon_name == NULL ||
+           host->my_name == NULL) {
+               free(host->my_name);
+               free(host->mon_name);
+               free(host->name);
+               free(host);
+               goto out_nomem;
        }
 
+       host->last_used = timestamp;
+       host->timeout = NSM_TIMEOUT;
+       host->retries = 100;            /* force address retry */
+
+       return host;
+
+out_nomem:
+       xlog_warn("Unable to allocate memory");
        return NULL;
 }
 
 static void smn_forget_host(struct nsm_host *host)
 {
-       unlink(host->path);
-       free(host->path);
+       xlog(D_CALL, "Removing %s (%s, %s) from notify list",
+                       host->name, host->mon_name, host->my_name);
+
+       nsm_delete_notified_host(host->name, host->mon_name, host->my_name);
+
+       free(host->my_name);
+       free(host->mon_name);
        free(host->name);
        if (host->ai)
                freeaddrinfo(host->ai);
@@ -158,13 +144,219 @@ static void smn_forget_host(struct nsm_host *host)
        free(host);
 }
 
+static unsigned int
+smn_get_host(const char *hostname,
+               __attribute__ ((unused)) const struct sockaddr *sap,
+               const struct mon *m, const time_t timestamp)
+{
+       struct nsm_host *host;
+
+       host = smn_alloc_host(hostname,
+               m->mon_id.mon_name, m->mon_id.my_id.my_name, timestamp);
+       if (host == NULL)
+               return 0;
+
+       insert_host(host);
+       xlog(D_GENERAL, "Added host %s to notify list", hostname);
+       return 1;
+}
+
+#ifdef IPV6_SUPPORTED
+static int smn_socket(void)
+{
+       int sock;
+
+       /*
+        * Use an AF_INET socket if IPv6 is disabled on the
+        * local system.
+        */
+       sock = socket(AF_INET6, SOCK_DGRAM, 0);
+       if (sock == -1) {
+               if (errno != EAFNOSUPPORT) {
+                       xlog(L_ERROR, "Failed to create RPC socket: %m");
+                       return -1;
+               }
+               sock = socket(AF_INET, SOCK_DGRAM, 0);
+               if (sock < 0) {
+                       xlog(L_ERROR, "Failed to create RPC socket: %m");
+                       return -1;
+               }
+       } else
+               nsm_family = AF_INET6;
+
+       if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
+               xlog(L_ERROR, "fcntl(3) on RPC socket failed: %m");
+               goto out_close;
+       }
+
+       /*
+        * TI-RPC over IPv6 (udp6/tcp6) does not handle IPv4.  However,
+        * since sm-notify open-codes all of its RPC support, it can
+        * use a single socket and let the local network stack provide
+        * the correct mapping between address families automatically.
+        * This is the same thing that is done in the kernel.
+        */
+       if (nsm_family == AF_INET6) {
+               const int zero = 0;
+               socklen_t zerolen = (socklen_t)sizeof(zero);
+
+               if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+                                       (char *)&zero, zerolen) == -1) {
+                       xlog(L_ERROR, "setsockopt(3) on RPC socket failed: %m");
+                       goto out_close;
+               }
+       }
+
+       return sock;
+
+out_close:
+       (void)close(sock);
+       return -1;
+}
+#else  /* !IPV6_SUPPORTED */
+static int smn_socket(void)
+{
+       int sock;
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock == -1) {
+               xlog(L_ERROR, "Failed to create RPC socket: %m");
+               return -1;
+       }
+
+       if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
+               xlog(L_ERROR, "fcntl(3) on RPC socket failed: %m");
+               (void)close(sock);
+               return -1;
+       }
+
+       return sock;
+}
+#endif /* !IPV6_SUPPORTED */
+
+/*
+ * If admin specified a source address or srcport, then convert those
+ * to a sockaddr and return it.   Otherwise, return an ANYADDR address.
+ */
+__attribute_malloc__
+static struct addrinfo *
+smn_bind_address(const char *srcaddr, const char *srcport)
+{
+       struct addrinfo *ai = NULL;
+       struct addrinfo hint = {
+               .ai_flags       = AI_NUMERICSERV,
+               .ai_family      = nsm_family,
+               .ai_protocol    = (int)IPPROTO_UDP,
+       };
+       int error;
+
+       if (srcaddr == NULL)
+               hint.ai_flags |= AI_PASSIVE;
+
+       if (srcport == NULL)
+               error = getaddrinfo(srcaddr, "", &hint, &ai);
+       else
+               error = getaddrinfo(srcaddr, srcport, &hint, &ai);
+       if (error != 0) {
+               xlog(L_ERROR,
+                       "Invalid bind address or port for RPC socket: %s",
+                               gai_strerror(error));
+               return NULL;
+       }
+
+       return ai;
+}
+
+#ifdef HAVE_LIBTIRPC
+static int
+smn_bindresvport(int sock, struct sockaddr *sap)
+{
+       return bindresvport_sa(sock, sap);
+}
+
+#else  /* !HAVE_LIBTIRPC */
+static int
+smn_bindresvport(int sock, struct sockaddr *sap)
+{
+       if (sap->sa_family != AF_INET) {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       return bindresvport(sock, (struct sockaddr_in *)(char *)sap);
+}
+#endif /* !HAVE_LIBTIRPC */
+
+/*
+ * Prepare a socket for sending RPC requests
+ *
+ * Returns a bound datagram socket file descriptor, or -1 if
+ * an error occurs.
+ */
+static int
+smn_create_socket(const char *srcaddr, const char *srcport)
+{
+       int sock, retry_cnt = 0;
+       struct addrinfo *ai;
+
+retry:
+       sock = smn_socket();
+       if (sock == -1)
+               return -1;
+
+       ai = smn_bind_address(srcaddr, srcport);
+       if (ai == NULL) {
+               (void)close(sock);
+               return -1;
+       }
+
+       /* Use source port if provided on the command line,
+        * otherwise use bindresvport */
+       if (srcport) {
+               if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
+                       xlog(L_ERROR, "Failed to bind RPC socket: %m");
+                       freeaddrinfo(ai);
+                       (void)close(sock);
+                       return -1;
+               }
+       } else {
+               struct servent *se;
+
+               if (smn_bindresvport(sock, ai->ai_addr) == -1) {
+                       xlog(L_ERROR,
+                               "bindresvport on RPC socket failed: %m");
+                       freeaddrinfo(ai);
+                       (void)close(sock);
+                       return -1;
+               }
+
+               /* try to avoid known ports */
+               se = getservbyport((int)nfs_get_port(ai->ai_addr), "udp");
+               if (se != NULL && retry_cnt < 100) {
+                       retry_cnt++;
+                       freeaddrinfo(ai);
+                       (void)close(sock);
+                       goto retry;
+               }
+       }
+
+       freeaddrinfo(ai);
+       return sock;
+}
+
 int
 main(int argc, char **argv)
 {
-       int     c;
-       int     force = 0;
+       int     c, sock, force = 0;
+       char *  progname;
 
-       while ((c = getopt(argc, argv, "dm:np:v:qP:f")) != -1) {
+       progname = strrchr(argv[0], '/');
+       if (progname != NULL)
+               progname++;
+       else
+               progname = argv[0];
+
+       while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) {
                switch (c) {
                case 'f':
                        force = 1;
@@ -176,32 +368,17 @@ main(int argc, char **argv)
                        opt_max_retry = atoi(optarg) * 60;
                        break;
                case 'n':
-                       opt_update_state = 0;
+                       opt_update_state = false;
                        break;
                case 'p':
-                       opt_srcport = atoi(optarg);
+                       opt_srcport = optarg;
                        break;
                case 'v':
                        opt_srcaddr = optarg;
                        break;
-               case 'q':
-                       opt_quiet = 1;
-                       break;
                case 'P':
-                       _SM_BASE_PATH = strdup(optarg);
-                       _SM_STATE_PATH = malloc(strlen(optarg)+1+sizeof("state"));
-                       _SM_DIR_PATH = malloc(strlen(optarg)+1+sizeof("sm"));
-                       _SM_BAK_PATH = malloc(strlen(optarg)+1+sizeof("sm.bak"));
-                       if (_SM_BASE_PATH == NULL ||
-                           _SM_STATE_PATH == NULL ||
-                           _SM_DIR_PATH == NULL ||
-                           _SM_BAK_PATH == NULL) {
-                               nsm_log(LOG_ERR, "unable to allocate memory");
+                       if (!nsm_setup_pathnames(argv[0], optarg))
                                exit(1);
-                       }
-                       strcat(strcpy(_SM_STATE_PATH, _SM_BASE_PATH), "/state");
-                       strcat(strcpy(_SM_DIR_PATH, _SM_BASE_PATH), "/sm");
-                       strcat(strcpy(_SM_BAK_PATH, _SM_BASE_PATH), "/sm.bak");
                        break;
 
                default:
@@ -211,18 +388,26 @@ main(int argc, char **argv)
 
        if (optind < argc) {
 usage:         fprintf(stderr,
-                       "Usage: sm-notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
-                       "            [-P /path/to/state/directory] [-v my_host_name]\n");
+                       "Usage: %s -notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
+                       "            [-P /path/to/state/directory] [-v my_host_name]\n",
+                       progname);
                exit(1);
        }
 
-       log_syslog = 1;
-       openlog("sm-notify", LOG_PID, LOG_DAEMON);
+       xlog_syslog(1);
+       if (opt_debug) {
+               xlog_stderr(1);
+               xlog_config(D_ALL, 1);
+       } else
+               xlog_stderr(0);
+
+       xlog_open(progname);
+       xlog(L_NOTICE, "Version " VERSION " starting");
 
-       if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) {
-               if (record_pid() == 0 && force == 0 && opt_update_state == 1) {
+       if (nsm_is_default_parentdir()) {
+               if (record_pid() == 0 && force == 0 && opt_update_state) {
                        /* already run, don't try again */
-                       nsm_log(LOG_NOTICE, "Already notifying clients; Exiting!");
+                       xlog(L_NOTICE, "Already notifying clients; Exiting!");
                        exit(0);
                }
        }
@@ -231,31 +416,26 @@ usage:            fprintf(stderr,
                strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
        } else
        if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
-               nsm_log(LOG_ERR, "Failed to obtain name of local host: %s",
-                       strerror(errno));
+               xlog(L_ERROR, "Failed to obtain name of local host: %m");
                exit(1);
        }
 
-       backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH);
-       get_hosts(_SM_BAK_PATH);
-
-       /* If there are not hosts to notify, just exit */
-       if (!hosts) {
-               nsm_log(LOG_DEBUG, "No hosts to notify; exiting");
+       (void)nsm_retire_monitored_hosts();
+       if (nsm_load_notify_list(smn_get_host) == 0) {
+               xlog(D_GENERAL, "No hosts to notify; exiting");
                return 0;
        }
 
-       /* Get and update the NSM state. This will call sync() */
        nsm_state = nsm_get_state(opt_update_state);
-       set_kernel_nsm_state(nsm_state);
+       if (nsm_state == 0)
+               exit(1);
+       nsm_update_kernel_state(nsm_state);
 
        if (!opt_debug) {
-               if (!opt_quiet)
-                       printf("Backgrounding to notify hosts...\n");
+               xlog(L_NOTICE, "Backgrounding to notify hosts...\n");
 
                if (daemon(0, 0) < 0) {
-                       nsm_log(LOG_ERR, "unable to background: %s",
-                                       strerror(errno));
+                       xlog(L_ERROR, "unable to background: %m");
                        exit(1);
                }
 
@@ -264,15 +444,21 @@ usage:            fprintf(stderr,
                close(2);
        }
 
-       notify();
+       sock = smn_create_socket(opt_srcaddr, opt_srcport);
+       if (sock == -1)
+               exit(1);
+
+       if (!nsm_drop_privileges(-1))
+               exit(1);
+
+       notify(sock);
 
        if (hosts) {
                struct nsm_host *hp;
 
                while ((hp = hosts) != 0) {
                        hosts = hp->next;
-                       nsm_log(LOG_NOTICE,
-                               "Unable to notify %s, giving up",
+                       xlog(L_NOTICE, "Unable to notify %s, giving up",
                                hp->name);
                }
                exit(1);
@@ -285,69 +471,13 @@ usage:            fprintf(stderr,
  * Notify hosts
  */
 static void
-notify(void)
+notify(const int sock)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *local_addr = (struct sockaddr *)&address;
        time_t  failtime = 0;
-       int     sock = -1;
-       int retry_cnt = 0;
-
- retry:
-       sock = socket(AF_INET, SOCK_DGRAM, 0);
-       if (sock < 0) {
-               nsm_log(LOG_ERR, "Failed to create RPC socket: %s",
-                       strerror(errno));
-               exit(1);
-       }
-       fcntl(sock, F_SETFL, O_NONBLOCK);
-
-       memset(&address, 0, sizeof(address));
-       local_addr->sa_family = AF_INET;        /* Default to IPv4 */
-
-       /* Bind source IP if provided on command line */
-       if (opt_srcaddr) {
-               struct addrinfo *ai = smn_lookup(opt_srcaddr);
-               if (!ai) {
-                       nsm_log(LOG_ERR,
-                               "Not a valid hostname or address: \"%s\"",
-                               opt_srcaddr);
-                       exit(1);
-               }
-
-               /* We know it's IPv4 at this point */
-               memcpy(local_addr, ai->ai_addr, ai->ai_addrlen);
-
-               freeaddrinfo(ai);
-       }
-
-       /* Use source port if provided on the command line,
-        * otherwise use bindresvport */
-       if (opt_srcport) {
-               smn_set_port(local_addr, opt_srcport);
-               if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) {
-                       nsm_log(LOG_ERR, "Failed to bind RPC socket: %s",
-                               strerror(errno));
-                       exit(1);
-               }
-       } else {
-               struct servent *se;
-               struct sockaddr_in *sin = (struct sockaddr_in *)local_addr;
-               (void) bindresvport(sock, sin);
-               /* try to avoid known ports */
-               se = getservbyport(sin->sin_port, "udp");
-               if (se && retry_cnt < 100) {
-                       retry_cnt++;
-                       close(sock);
-                       goto retry;
-               }
-       }
 
        if (opt_max_retry)
                failtime = time(NULL) + opt_max_retry;
 
-       drop_privs();
-
        while (hosts) {
                struct pollfd   pfd;
                time_t          now = time(NULL);
@@ -383,7 +513,7 @@ notify(void)
                if (hosts == NULL)
                        return;
 
-               nsm_log(LOG_DEBUG, "Host %s due in %ld seconds",
+               xlog(D_GENERAL, "Host %s due in %ld seconds",
                                hosts->name, wait);
 
                pfd.fd = sock;
@@ -405,34 +535,18 @@ notify(void)
 static int
 notify_host(int sock, struct nsm_host *host)
 {
-       struct sockaddr_storage address;
-       struct sockaddr *dest = (struct sockaddr *)&address;
-       socklen_t destlen = sizeof(address);
-       static unsigned int     xid = 0;
-       uint32_t                msgbuf[MAXMSGSIZE], *p;
-       unsigned int            len;
-
-       if (!xid)
-               xid = getpid() + time(NULL);
-       if (!host->xid)
-               host->xid = xid++;
+       struct sockaddr *sap;
+       socklen_t salen;
 
        if (host->ai == NULL) {
                host->ai = smn_lookup(host->name);
                if (host->ai == NULL) {
-                       nsm_log(LOG_WARNING,
-                               "DNS resolution of %s failed; "
+                       xlog_warn("DNS resolution of %s failed; "
                                "retrying later", host->name);
                        return 0;
                }
        }
 
-       memset(msgbuf, 0, sizeof(msgbuf));
-       p = msgbuf;
-       *p++ = htonl(host->xid);
-       *p++ = 0;
-       *p++ = htonl(2);
-
        /* If we retransmitted 4 times, reset the port to force
         * a new portmap lookup (in case statd was restarted).
         * We also rotate through multiple IP addresses at this
@@ -440,10 +554,7 @@ notify_host(int sock, struct nsm_host *host)
         */
        if (host->retries >= 4) {
                /* don't rotate if there is only one addrinfo */
-               if (host->ai->ai_next == NULL)
-                       memcpy(&host->addr, host->ai->ai_addr,
-                                               host->ai->ai_addrlen);
-               else {
+               if (host->ai->ai_next != NULL) {
                        struct addrinfo *first = host->ai;
                        struct addrinfo **next = &host->ai;
 
@@ -456,213 +567,100 @@ notify_host(int sock, struct nsm_host *host)
                                next = & (*next)->ai_next;
                        /* put first entry at end */
                        *next = first;
-                       memcpy(&host->addr, first->ai_addr,
-                                               first->ai_addrlen);
                }
 
-               smn_set_port((struct sockaddr *)&host->addr, 0);
+               nfs_set_port(host->ai->ai_addr, 0);
                host->retries = 0;
        }
 
-       memcpy(dest, &host->addr, destlen);
-       if (smn_get_port(dest) == 0) {
-               /* Build a PMAP packet */
-               nsm_log(LOG_DEBUG, "Sending portmap query to %s", host->name);
+       sap = host->ai->ai_addr;
+       salen = host->ai->ai_addrlen;
 
-               smn_set_port(dest, 111);
-               *p++ = htonl(100000);
-               *p++ = htonl(2);
-               *p++ = htonl(3);
-
-               /* Auth and verf */
-               *p++ = 0; *p++ = 0;
-               *p++ = 0; *p++ = 0;
-
-               *p++ = htonl(NSM_PROGRAM);
-               *p++ = htonl(NSM_VERSION);
-               *p++ = htonl(IPPROTO_UDP);
-               *p++ = 0;
-       } else {
-               /* Build an SM_NOTIFY packet */
-               nsm_log(LOG_DEBUG, "Sending SM_NOTIFY to %s", host->name);
-
-               *p++ = htonl(NSM_PROGRAM);
-               *p++ = htonl(NSM_VERSION);
-               *p++ = htonl(NSM_NOTIFY);
-
-               /* Auth and verf */
-               *p++ = 0; *p++ = 0;
-               *p++ = 0; *p++ = 0;
-
-               /* state change */
-               len = strlen(nsm_hostname);
-               *p++ = htonl(len);
-               memcpy(p, nsm_hostname, len);
-               p += (len + 3) >> 2;
-               *p++ = htonl(nsm_state);
-       }
-       len = (p - msgbuf) << 2;
-
-       if (sendto(sock, msgbuf, len, 0, dest, destlen) < 0)
-               nsm_log(LOG_WARNING, "Sending Reboot Notification to "
-                       "'%s' failed: errno %d (%s)", host->name, errno, strerror(errno));
+       if (nfs_get_port(sap) == 0)
+               host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
+       else
+               host->xid = nsm_xmit_notify(sock, sap, salen,
+                               SM_PROG, nsm_hostname, nsm_state);
        
        return 0;
 }
 
 /*
- * Receive reply from remote host
+ * Extract the returned port number and set up the SM_NOTIFY call.
  */
 static void
-recv_reply(int sock)
+recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
 {
-       struct nsm_host *hp;
-       struct sockaddr *sap;
-       uint32_t        msgbuf[MAXMSGSIZE], *p, *end;
-       uint32_t        xid;
-       int             res;
-
-       res = recv(sock, msgbuf, sizeof(msgbuf), 0);
-       if (res < 0)
-               return;
-
-       nsm_log(LOG_DEBUG, "Received packet...");
+       uint16_t port = nsm_recv_rpcbind(sap->sa_family, xdr);
 
-       p = msgbuf;
-       end = p + (res >> 2);
-
-       xid = ntohl(*p++);
-       if (*p++ != htonl(1)    /* must be REPLY */
-        || *p++ != htonl(0)    /* must be ACCEPTED */
-        || *p++ != htonl(0)    /* must be NULL verifier */
-        || *p++ != htonl(0)
-        || *p++ != htonl(0))   /* must be SUCCESS */
-               return;
+       host->send_next = time(NULL);
+       host->xid = 0;
 
-       /* Before we look at the data, find the host struct for
-          this reply */
-       if ((hp = find_host(xid)) == NULL)
-               return;
-       sap = (struct sockaddr *)&hp->addr;
-
-       if (smn_get_port(sap) == 0) {
-               /* This was a portmap request */
-               unsigned int    port;
-
-               port = ntohl(*p++);
-               if (p > end)
-                       goto fail;
-
-               hp->send_next = time(NULL);
-               if (port == 0) {
-                       /* No binding for statd. Delay the next
-                        * portmap query for max timeout */
-                       nsm_log(LOG_DEBUG, "No statd on %s", hp->name);
-                       hp->timeout = NSM_MAX_TIMEOUT;
-                       hp->send_next += NSM_MAX_TIMEOUT;
-               } else {
-                       smn_set_port(sap, port);
-                       if (hp->timeout >= NSM_MAX_TIMEOUT / 4)
-                               hp->timeout = NSM_MAX_TIMEOUT / 4;
-               }
-               hp->xid = 0;
+       if (port == 0) {
+               /* No binding for statd... */
+               xlog(D_GENERAL, "No statd on host %s", host->name);
+               host->timeout = NSM_MAX_TIMEOUT;
+               host->send_next += NSM_MAX_TIMEOUT;
        } else {
-               /* Successful NOTIFY call. Server returns void,
-                * so nothing we need to do here (except
-                * check that we didn't read past the end of the
-                * packet)
-                */
-               if (p <= end) {
-                       nsm_log(LOG_DEBUG, "Host %s notified successfully",
-                                       hp->name);
-                       smn_forget_host(hp);
-                       return;
-               }
+               nfs_set_port(sap, port);
+               if (host->timeout >= NSM_MAX_TIMEOUT / 4)
+                       host->timeout = NSM_MAX_TIMEOUT / 4;
        }
 
-fail:  /* Re-insert the host */
-       insert_host(hp);
+       insert_host(host);
 }
 
 /*
- * Back up all hosts from the sm directory to sm.bak
+ * Successful NOTIFY call. Server returns void, so nothing
+ * we need to do here.
  */
 static void
-backup_hosts(const char *dirname, const char *bakname)
+recv_notify_reply(struct nsm_host *host)
 {
-       struct dirent   *de;
-       DIR             *dir;
-
-       if (!(dir = opendir(dirname))) {
-               nsm_log(LOG_WARNING,
-                       "Failed to open %s: %s", dirname, strerror(errno));
-               return;
-       }
+       xlog(D_GENERAL, "Host %s notified successfully", host->name);
 
-       while ((de = readdir(dir)) != NULL) {
-               char    src[1024], dst[1024];
-
-               if (de->d_name[0] == '.')
-                       continue;
-
-               snprintf(src, sizeof(src), "%s/%s", dirname, de->d_name);
-               snprintf(dst, sizeof(dst), "%s/%s", bakname, de->d_name);
-               if (rename(src, dst) < 0) {
-                       nsm_log(LOG_WARNING,
-                               "Failed to rename %s -> %s: %m",
-                               src, dst);
-               }
-       }
-       closedir(dir);
+       smn_forget_host(host);
 }
 
 /*
- * Get all entries from sm.bak and convert them to host entries
+ * Receive reply from remote host
  */
 static void
-get_hosts(const char *dirname)
+recv_reply(int sock)
 {
-       struct nsm_host *host;
-       struct dirent   *de;
-       DIR             *dir;
+       struct nsm_host *hp;
+       struct sockaddr *sap;
+       char msgbuf[NSM_MAXMSGSIZE];
+       uint32_t        xid;
+       ssize_t         msglen;
+       XDR             xdr;
 
-       if (!(dir = opendir(dirname))) {
-               nsm_log(LOG_WARNING,
-                       "Failed to open %s: %s", dirname, strerror(errno));
+       memset(msgbuf, 0 , sizeof(msgbuf));
+       msglen = recv(sock, msgbuf, sizeof(msgbuf), 0);
+       if (msglen < 0)
                return;
-       }
-
-       host = NULL;
-       while ((de = readdir(dir)) != NULL) {
-               struct stat     stb;
-               char            path[1024];
 
-               if (de->d_name[0] == '.')
-                       continue;
-               if (host == NULL)
-                       host = calloc(1, sizeof(*host));
-               if (host == NULL) {
-                       nsm_log(LOG_WARNING, "Unable to allocate memory");
-                       return;
-               }
+       xlog(D_GENERAL, "Received packet...");
 
-               snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
-               if (stat(path, &stb) < 0)
-                       continue;
+       memset(&xdr, 0, sizeof(xdr));
+       xdrmem_create(&xdr, msgbuf, (unsigned int)msglen, XDR_DECODE);
+       xid = nsm_parse_reply(&xdr);
+       if (xid == 0)
+               goto out;
 
-               host->last_used = stb.st_mtime;
-               host->timeout = NSM_TIMEOUT;
-               host->path = strdup(path);
-               host->name = strdup(de->d_name);
-               host->retries = 100; /* force address retry */
+       /* Before we look at the data, find the host struct for
+          this reply */
+       if ((hp = find_host(xid)) == NULL)
+               goto out;
 
-               insert_host(host);
-               host = NULL;
-       }
-       closedir(dir);
+       sap = hp->ai->ai_addr;
+       if (nfs_get_port(sap) == 0)
+               recv_rpcbind_reply(sap, hp, &xdr);
+       else
+               recv_notify_reply(hp);
 
-       if (host)
-               free(host);
+out:
+       xdr_destroy(&xdr);
 }
 
 /*
@@ -712,84 +710,6 @@ find_host(uint32_t xid)
        return NULL;
 }
 
-
-/*
- * Retrieve the current NSM state
- */
-static unsigned int
-nsm_get_state(int update)
-{
-       char            newfile[PATH_MAX];
-       int             fd, state;
-
-       if ((fd = open(_SM_STATE_PATH, O_RDONLY)) < 0) {
-               if (!opt_quiet) {
-                       nsm_log(LOG_WARNING, "%s: %m", _SM_STATE_PATH);
-                       nsm_log(LOG_WARNING, "Creating %s, set initial state 1",
-                               _SM_STATE_PATH);
-               }
-               state = 1;
-               update = 1;
-       } else {
-               if (read(fd, &state, sizeof(state)) != sizeof(state)) {
-                       nsm_log(LOG_WARNING,
-                               "%s: bad file size, setting state = 1",
-                               _SM_STATE_PATH);
-                       state = 1;
-                       update = 1;
-               } else {
-                       if (!(state & 1))
-                               state += 1;
-               }
-               close(fd);
-       }
-
-       if (update) {
-               state += 2;
-               snprintf(newfile, sizeof(newfile),
-                               "%s.new", _SM_STATE_PATH);
-               if ((fd = open(newfile, O_CREAT|O_WRONLY, 0644)) < 0) {
-                       nsm_log(LOG_ERR, "Cannot create %s: %m", newfile);
-                       exit(1);
-               }
-               if (write(fd, &state, sizeof(state)) != sizeof(state)) {
-                       nsm_log(LOG_ERR,
-                               "Failed to write state to %s", newfile);
-                       exit(1);
-               }
-               close(fd);
-               if (rename(newfile, _SM_STATE_PATH) < 0) {
-                       nsm_log(LOG_ERR,
-                               "Cannot create %s: %m", _SM_STATE_PATH);
-                       exit(1);
-               }
-               sync();
-       }
-
-       return state;
-}
-
-/*
- * Log a message
- */
-static void
-nsm_log(int fac, const char *fmt, ...)
-{
-       va_list ap;
-
-       if (fac == LOG_DEBUG && !opt_debug)
-               return;
-
-       va_start(ap, fmt);
-       if (log_syslog)
-               vsyslog(fac, fmt, ap);
-       else {
-               vfprintf(stderr, fmt, ap);
-               fputs("\n", stderr);
-       }
-       va_end(ap);
-}
-
 /*
  * Record pid in /var/run/sm-notify.pid
  * This file should remain until a reboot, even if the
@@ -799,61 +719,20 @@ nsm_log(int fac, const char *fmt, ...)
 static int record_pid(void)
 {
        char pid[20];
+       ssize_t len;
        int fd;
 
-       snprintf(pid, 20, "%d\n", getpid());
+       (void)snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
        fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
        if (fd < 0)
                return 0;
-       if (write(fd, pid, strlen(pid)) != strlen(pid))  {
-               nsm_log(LOG_WARNING, "Writing to pid file failed: errno %d(%s)",
-                       errno, strerror(errno));
-       }
-       close(fd);
-       return 1;
-}
 
-/* Drop privileges to match owner of state-directory
- * (in case a reply triggers some unknown bug).
- */
-static void drop_privs(void)
-{
-       struct stat st;
-
-       if (stat(_SM_DIR_PATH, &st) == -1 &&
-           stat(_SM_BASE_PATH, &st) == -1) {
-               st.st_uid = 0;
-               st.st_gid = 0;
-       }
-
-       if (st.st_uid == 0) {
-               nsm_log(LOG_WARNING,
-                       "sm-notify running as root. chown %s to choose different user",
-                   _SM_DIR_PATH);
-               return;
-       }
-
-       setgroups(0, NULL);
-       if (setgid(st.st_gid) == -1
-           || setuid(st.st_uid) == -1) {
-               nsm_log(LOG_ERR, "Fail to drop privileges");
-               exit(1);
+       len = write(fd, pid, strlen(pid));
+       if ((len < 0) || ((size_t)len != strlen(pid))) {
+               xlog_warn("Writing to pid file failed: errno %d (%m)",
+                               errno);
        }
-}
 
-static void set_kernel_nsm_state(int state)
-{
-       int fd;
-       const char *file = "/proc/sys/fs/nfs/nsm_local_state";
-
-       fd = open(file ,O_WRONLY);
-       if (fd >= 0) {
-               char buf[20];
-               snprintf(buf, sizeof(buf), "%d", state);
-               if (write(fd, buf, strlen(buf)) != strlen(buf)) {
-                       nsm_log(LOG_WARNING, "Writing to '%s' failed: errno %d (%s)",
-                               file, errno, strerror(errno));
-               }
-               close(fd);
-       }
+       (void)close(fd);
+       return 1;
 }
index dd03b8dabbc15507316882136ab167694c96e312..163713ebe5963f7af0d7dc2cff0020f958e43f18 100644 (file)
-.\"
-.\" sm-notify(8)
+.\"@(#)sm-notify.8"
 .\"
 .\" Copyright (C) 2004 Olaf Kirch <okir@suse.de>
-.TH sm-notify 8 "19 Mar 2007
+.\"
+.\" Rewritten by Chuck Lever <chuck.lever@oracle.com>, 2009.
+.\" Copyright 2009 Oracle.  All rights reserved.
+.\"
+.TH SM-NOTIFY 8 "1 November 2009
 .SH NAME
-sm-notify \- Send out NSM reboot notifications
+sm-notify \- send reboot notifications to NFS peers
 .SH SYNOPSIS
-.BI "/sbin/sm-notify [-dfq] [-m " time "] [-p " port "] [-P " path "] [-v " my_name " ]
+.BI "/usr/sbin/sm-notify [-dfn] [-m " minutes "] [-v " name "] [-p " notify-port "] [-P " path "]
 .SH DESCRIPTION
-File locking over NFS (v2 and v3) requires a facility to notify peers in
-case of a reboot, so that clients can reclaim locks after
-a server crash, and/or
-servers can release locks held by the rebooted client.
+File locks are not part of persistent file system state.
+Lock state is thus lost when a host reboots.
+.PP
+Network file systems must also detect when lock state is lost
+because a remote host has rebooted.
+After an NFS client reboots, an NFS server must release all file locks
+held by applications that were running on that client.
+After a server reboots, a client must remind the
+server of file locks held by applications running on that client.
 .PP
-This is a two-step process: during normal
-operations, a mechanism is required to keep track of which
-hosts need to be informed of a reboot. And of course,
-notifications need to be sent out during reboot.
-The protocol used for this is called NSM, for
-.IR "Network Status Monitor" .
+For NFS version 2 and version 3, the
+.I Network Status Monitor
+protocol (or NSM for short)
+is used to notify NFS peers of reboots.
+On Linux, two separate user-space components constitute the NSM service:
+.TP
+.B sm-notify
+A helper program that notifies NFS peers after the local system reboots
+.TP
+.B rpc.statd
+A daemon that listens for reboot notifications from other hosts, and
+manages the list of hosts to be notified when the local system reboots
 .PP
-This implementation separates these into separate program.
+The local NFS lock manager alerts its local
 .B rpc.statd
-tracks hosts which need to be notified and this
+of each remote peer that should be monitored.
+When the local system reboots, the
 .B sm-notify
-performs the notification.  When
+command notifies the NSM service on monitored peers of the reboot.
+When a remote reboots, that peer notifies the local
+.BR rpc.statd ,
+which in turn passes the reboot notification
+back to the local NFS lock manager.
+.SH NSM OPERATION IN DETAIL
+The first file locking interaction between an NFS client and server causes
+the NFS lock managers on both peers to contact their local NSM service to
+store information about the opposite peer.
+On Linux, the local lock manager contacts
+.BR rpc.statd .
+.PP
+.B rpc.statd
+records information about each monitored NFS peer on persistent storage.
+This information describes how to contact a remote peer
+in case the local system reboots,
+how to recognize which monitored peer is reporting a reboot,
+and how to notify the local lock manager when a monitored peer
+indicates it has rebooted.
+.PP
+An NFS client sends a hostname, known as the client's
+.IR caller_name ,
+in each file lock request.
+An NFS server can use this hostname to send asynchronous GRANT
+calls to a client, or to notify the client it has rebooted.
+.PP
+The Linux NFS server can provide the client's
+.I caller_name
+or the client's network address to
+.BR rpc.statd .
+For the purposes of the NSM protocol,
+this name or address is known as the monitored peer's
+.IR mon_name .
+In addition, the local lock manager tells
 .B rpc.statd
-is started it will typically started
+what it thinks its own hostname is.
+For the purposes of the NSM protocol,
+this hostname is known as
+.IR my_name .
+.PP
+There is no equivalent interaction between an NFS server and a client
+to inform the client of the server's
+.IR caller_name .
+Therefore NFS clients do not actually know what
+.I mon_name
+an NFS server might use in an SM_NOTIFY request.
+The Linux NFS client records the server's hostname used on the mount command
+to identify rebooting NFS servers.
+.SS Reboot notification
+When the local system reboots, the
+.B sm-notify
+command reads the list of monitored peers from persistent storage and
+sends an SM_NOTIFY request to the NSM service on each listed remote peer.
+It uses the
+.I mon_name
+string as the destination.
+To identify which host has rebooted, the
 .B sm-notify
-but this is configurable.
-.SS Operation
-For each NFS client or server machine to be monitored,
+command normally sends the results of
+.BR gethostname (3)
+as the
+.I my_name
+string.
+The remote
 .B rpc.statd
-creates a file in
-.BR /var/lib/nfs/sm ", "
-and removes the file if monitoring is no longer required.
+matches incoming SM_NOTIFY requests using this string,
+or the caller's network address,
+to one or more peers on its own monitor list.
 .PP
-When the machine is rebooted,
+If
+.B rpc.statd
+does not find a peer on its monitor list that matches
+an incoming SM_NOTIFY request,
+the notification is not forwarded to the local lock manager.
+In addition, each peer has its own
+.IR "NSM state number" ,
+a 32-bit integer that is bumped after each reboot by the
 .B sm-notify
-iterates through these files and notifies the peer
-.B statd
-server on those machines.
+command.
+.B rpc.statd
+uses this number to distinguish between actual reboots
+and replayed notifications.
 .PP
-Each machine has an
-.I "NSM state" ,
-which is basically an integer counter that is incremented
-each time the machine reboots. This counter is stored
-in
-.BR /var/lib/nfs/state ,
-and updated by
-.BR sm-notify .
-.SS Security
-.B sm-notify
-has little need for root privileges and so drops them as soon as
-possible.
-It continues to need to make changes to the
-.B sm
-and
-.B sm.bak
-directories so to be able to drop privileges, these must be writable
-by a non-privileged user.  If these directories are owned by a
-non-root user,
-.B sm-notify
-will drop privilege to match that user once it has created sockets for
-sending out request (for which it needs privileged) but before it
-processes any reply (which is the most likely source of possible
-privilege abuse).
+Part of NFS lock recovery is rediscovering
+which peers need to be monitored again.
+The
+.B sm-notify
+command clears the monitor list on persistent storage after each reboot.
 .SH OPTIONS
 .TP
-.BI -m " failtime
-When notifying hosts,
+.B -d
+Keeps
+.B sm-notify
+attached to its controlling terminal and running in the foreground
+so that notification progress may be monitored directly.
+.TP
+.B -f
+Send notifications even if
+.B sm-notify
+has already run since the last system reboot.
+.TP
+.BI -m " retry-time
+Specifies the length of time, in minutes, to continue retrying
+notifications to unresponsive hosts.
+If this option is not specified,
 .B sm-notify
-will try to contact each host for up to 15 minutes,
-and will give up if unable to reach it within this time
-frame.
+attempts to send notifications for 15 minutes.
+Specifying a value of 0 causes
+.B sm-notify
+to continue sending notifications to unresponsive peers
+until it is manually killed.
+.IP
+Notifications are retried if sending fails,
+the remote does not respond,
+the remote's NSM service is not registered,
+or if there is a DNS failure
+which prevents the remote's
+.I mon_name
+from being resolved to an address.
 .IP
-Using the
-.B -m
-option, you can override this. A value of 0 tells
-sm-notify to retry indefinitely; any other value is
-interpreted as the maximum retry time in minutes.
+Hosts are not removed from the notification list until a valid
+reply has been received.
+However, the SM_NOTIFY procedure has a void result.
+There is no way for
+.B sm-notify
+to tell if the remote recognized the sender and has started
+appropriate lock recovery.
 .TP
-.BI -v " ipaddr-or-hostname
-This option tells
-.B sm-notify
-to bind to the specified
-.IR ipaddr ,
-(or the ipaddr of the given
-.IR hostname )
-so that all notification packets originate from this address.
-This is useful for NFS failover.  The given name is also used as the
-.I name
-of this host in the NSM request.
+.B -n
+Prevents
+.B sm-notify
+from updating the local system's NSM state number.
 .TP
 .BI -p " port
-instructs
+Specifies the source port number
 .B sm-notify
-to bind to the indicated IP
-.IR port
-number. If this option is not given, it will try to bind to
-a randomly chosen privileged port below 1024.
-.TP
-.B -q
-Be quiet. This suppresses all messages except error
-messages while collecting the list of hosts.
+should use when sending reboot notifications.
+If this option is not specified, a randomly chosen ephemeral port is used.
+.IP
+This option can be used to traverse a firewall between client and server.
 .TP
-.BI -P " /path/to/state/directory
-If
+.BI "\-P, " "" \-\-state\-directory\-path " pathname
+Specifies the pathname of the parent directory
+where NSM state information resides.
+If this option is not specified,
+.B sm-notify
+uses
+.I /var/lib/nfs
+by default.
+.IP
+After starting,
 .B sm-notify
-should look in a no-standard place of state file, the path can be
-given here.  The directories
-.B sm
-and
-.B sm.bak
-and the file
-.B state
-must exist in that directory with the standard names.
+attempts to set its effective UID and GID to the owner
+and group of this directory.
 .TP
-.B -f
-If the state path has not been reset with
-.BR -P ,
+.BI -v " ipaddr " | " hostname
+Specifies the network address from which to send reboot notifications,
+and the
+.I mon_name
+argument to use when sending SM_NOTIFY requests.
+If this option is not specified,
 .B sm-notify
-will normally create a file in
-.B /var/run
-to indicate that it has been
-run.  If this file is found when
+uses a wildcard address as the transport bind address,
+and uses the results of
+.BR gethostname (3)
+as the
+.I mon_name
+argument.
+.IP
+The
+.I ipaddr
+form can be expressed as either an IPv4 or an IPv6 presentation address.
+.IP
+This option can be useful in multi-homed configurations where
+the remote requires notification from a specific network address.
+.SH SECURITY
+The
 .B sm-notify
-starts, it will not run again (as it is normally only needed once per
-reboot).
-If
-.B -f
-(for
-.BR force )
-is given,
+command must be started as root to acquire privileges needed
+to access the state information database.
+It drops root privileges
+as soon as it starts up to reduce the risk of a privilege escalation attack.
+.PP
+During normal operation,
+the effective user ID it chooses is the owner of the state directory.
+This allows it to continue to access files in that directory after it
+has dropped its root privileges.
+To control which user ID
+.B rpc.statd
+chooses, simply use
+.BR chown (1)
+to set the owner of
+the state directory.
+.SH ADDITIONAL NOTES
+Lock recovery after a reboot is critical to maintaining data integrity
+and preventing unnecessary application hangs.
+.PP
+To help
+.B rpc.statd
+match SM_NOTIFY requests to NLM requests, a number of best practices
+should be observed, including:
+.IP
+The UTS nodename of your systems should match the DNS names that NFS
+peers use to contact them
+.IP
+The UTS nodenames of your systems should always be fully qualified domain names
+.IP
+The forward and reverse DNS mapping of the UTS nodenames should be
+consistent
+.IP
+The hostname the client uses to mount the server should match the server's
+.I mon_name
+in SM_NOTIFY requests it sends
+.IP
+The use of network addresses as a
+.I mon_name
+or a
+.I my_name
+string should be avoided when
+interoperating with non-Linux NFS implementations.
+.PP
+Unmounting an NFS file system does not necessarily stop
+either the NFS client or server from monitoring each other.
+Both may continue monitoring each other for a time in case subsequent
+NFS traffic between the two results in fresh mounts and additional
+file locking.
+.PP
+On Linux, if the
+.B lockd
+kernel module is unloaded during normal operation,
+all remote NFS peers are unmonitored.
+This can happen on an NFS client, for example,
+if an automounter removes all NFS mount
+points due to inactivity.
+.SS IPv6 and TI-RPC support
+TI-RPC is a pre-requisite for supporting NFS on IPv6.
+If TI-RPC support is built into the
 .B sm-notify
-will run even if the file in
-.B /var/run
-is present.
-.TP
-.B -n
-Do not update the NSM state. This is for testing only.  Setting this
-flag implies
-.BR -f .
-.TP
-.B -d
-Enables debugging.
-By default,
+command ,it will choose an appropriate IPv4 or IPv6 transport
+based on the network address returned by DNS for each remote peer.
+It should be fully compatible with remote systems
+that do not support TI-RPC or IPv6.
+.PP
+Currently, the
 .B sm-notify
-forks and puts itself in the background after obtaining the
-list of hosts from
-.BR /var/lib/nfs/sm .
+command supports sending notification only via datagram transport protocols.
 .SH FILES
-.BR /var/lib/nfs/state
-.br
-.BR /var/lib/nfs/sm/*
+.TP 2.5i
+.I /var/lib/nfs/sm
+directory containing monitor list
+.TP 2.5i
+.I /var/lib/nfs/sm.bak
+directory containing notify list
+.TP 2.5i
+.I /var/lib/nfs/state
+NSM state number for this host
+.TP 2.5i
+.I /proc/sys/fs/nfs/nsm_local_state
+kernel's copy of the NSM state number
+.SH SEE ALSO
+.BR rpc.statd (8),
+.BR nfs (5),
+.BR uname (2),
+.BR hostname (7)
+.PP
+RFC 1094 - "NFS: Network File System Protocol Specification"
 .br
-.BR /var/lib/nfs/sm.bak/*
+RFC 1813 - "NFS Version 3 Protocol Specification"
 .br
-.BR /var/run/sm-notify.pid
-.SH SEE ALSO
-.BR rpc.nfsd(8),
-.BR portmap(8)
+OpenGroup Protocols for Interworking: XNFS, Version 3W - Chapter 11
 .SH AUTHORS
-.br
 Olaf Kirch <okir@suse.de>
+.br
+Chuck Lever <chuck.lever@oracle.com>
diff --git a/utils/statd/sm_inter.x b/utils/statd/sm_inter.x
deleted file mode 100644 (file)
index d8e0ad7..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 1986 Sun Microsystems, Inc.
- * Modified by Jeffrey A. Uphoff, 1995, 1997-1999.
- * Modified by Olaf Kirch, 1996.
- * Modified by H.J. Lu, 1998.
- *
- * NSM for Linux.
- */
-
-/*
- * Copyright (c) 2009, Sun Microsystems, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * - Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- * - 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.
- * - Neither the name of Sun Microsystems, Inc. nor the names of its
- *   contributors may be used to endorse or promote products derived
- *   from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
- */
-
-/*
- * Status monitor protocol specification
- */
-
-#ifdef RPC_CLNT
-%#include <string.h>
-#endif
-
-program SM_PROG { 
-       version SM_VERS  {
-               /* res_stat = stat_succ if status monitor agrees to monitor */
-               /* res_stat = stat_fail if status monitor cannot monitor */
-               /* if res_stat == stat_succ, state = state number of site sm_name */
-               struct sm_stat_res                       SM_STAT(struct sm_name) = 1;
-
-               /* res_stat = stat_succ if status monitor agrees to monitor */
-               /* res_stat = stat_fail if status monitor cannot monitor */
-               /* stat consists of state number of local site */
-               struct sm_stat_res                       SM_MON(struct mon) = 2;
-
-               /* stat consists of state number of local site */
-               struct sm_stat                           SM_UNMON(struct mon_id) = 3;
-
-               /* stat consists of state number of local site */
-               struct sm_stat                           SM_UNMON_ALL(struct my_id) = 4;
-
-               void                                     SM_SIMU_CRASH(void) = 5;
-
-               void                                     SM_NOTIFY(struct stat_chge) = 6;
-
-       } = 1;
-} = 100024;
-
-const  SM_MAXSTRLEN = 1024;
-const  SM_PRIV_SIZE = 16;
-
-struct sm_name {
-       string mon_name<SM_MAXSTRLEN>;
-};
-
-struct my_id {
-       string   my_name<SM_MAXSTRLEN>;         /* name of the site iniates the monitoring request*/
-       int     my_prog;                        /* rpc program # of the requesting process */
-       int     my_vers;                        /* rpc version # of the requesting process */
-       int     my_proc;                        /* rpc procedure # of the requesting process */
-};
-
-struct mon_id {
-       string  mon_name<SM_MAXSTRLEN>;         /* name of the site to be monitored */
-       struct my_id my_id;
-};
-
-
-struct mon {
-       struct mon_id mon_id;
-       opaque priv[SM_PRIV_SIZE];              /* private information to store at monitor for requesting process */
-};
-
-struct stat_chge {
-       string  mon_name<SM_MAXSTRLEN>;         /* name of the site that had the state change */
-       int     state;
-};
-
-/*
- * state # of status monitor monitonically increases each time
- * status of the site changes:
- * an even number (>= 0) indicates the site is down and
- * an odd number (> 0) indicates the site is up;
- */
-struct sm_stat {
-       int state;              /* state # of status monitor */
-};
-
-enum res {
-       stat_succ = 0,          /* status monitor agrees to monitor */
-       stat_fail = 1           /* status monitor cannot monitor */
-};
-
-struct sm_stat_res {
-       res res_stat;
-       int state;
-};
-
-/* 
- * structure of the status message sent back by the status monitor
- * when monitor site status changes
- */
-struct status {
-       string mon_name<SM_MAXSTRLEN>;
-       int state;
-       opaque priv[SM_PRIV_SIZE]; /* stored private information */
-};
-
-%#define SM_INTER_X
index 799239f1d956f668c0cf2c79c98175914740b0b4..8d8b65e2f747b50cec285b0cc662a7dda81d3567 100644 (file)
@@ -12,7 +12,7 @@
 #include <netdb.h>
 #include "statd.h"
 
-/* 
+/*
  * Services SM_STAT requests.
  *
  * According the the X/Open spec's on this procedure: "Implementations
  *      other way to get it.
  *   3/ That's what we always did in the past.
  */
-struct sm_stat_res * 
-sm_stat_1_svc (struct sm_name *argp, struct svc_req *rqstp)
+struct sm_stat_res *
+sm_stat_1_svc(struct sm_name *argp,
+               __attribute__ ((unused)) struct svc_req *rqstp)
 {
   static sm_stat_res result;
+  char *name;
+
+  xlog(D_CALL, "Received SM_STAT from %s", argp->mon_name);
 
-  if (gethostbyname (argp->mon_name) == NULL) {
-    note (N_WARNING, "gethostbyname error for %s", argp->mon_name);
+  name = statd_canonical_name(argp->mon_name);
+  if (name == NULL) {
     result.res_stat = STAT_FAIL;
-    dprintf (N_DEBUG, "STAT_FAIL for %s", argp->mon_name);
+    xlog (D_GENERAL, "STAT_FAIL for %s", argp->mon_name);
   } else {
     result.res_stat = STAT_SUCC;
-    dprintf (N_DEBUG, "STAT_SUCC for %s", argp->mon_name);
+    xlog (D_GENERAL, "STAT_SUCC for %s", argp->mon_name);
+    free(name);
   }
   result.state = MY_STATE;
   return(&result);
index 1c5247ea2365aa0112ecda69956b95e04862d014..01fdb41301889bf6f36d6d68d5cc4d6b51673b33 100644 (file)
 #include <sys/resource.h>
 #include <sys/wait.h>
 #include <grp.h>
+
 #include "statd.h"
-#include "version.h"
 #include "nfslib.h"
+#include "nsm.h"
 
 /* Socket operations */
 #include <sys/types.h>
 #include <sys/socket.h>
 
-/* Added to enable specification of state directory path at run-time
- * j_carlos_gomez@yahoo.com
- */
-
-char * DIR_BASE = DEFAULT_DIR_BASE;
-
-char *  SM_DIR = DEFAULT_SM_DIR;
-char *  SM_BAK_DIR =  DEFAULT_SM_BAK_DIR;
-char *  SM_STAT_PATH = DEFAULT_SM_STAT_PATH;
-
-/* ----- end of state directory path stuff ------- */
-
 int    run_mode = 0;           /* foreground logging mode */
 
 /* LH - I had these local to main, but it seemed silly to have 
  * two copies of each - one in main(), one static in log.c... 
  * It also eliminates the 256-char static in log.c */
-char *name_p = NULL;
-const char *version_p = NULL;
+static char *name_p = NULL;
 
 /* PRC: a high-availability callout program can be specified with -H
  * When this is done, the program will receive callouts whenever clients
@@ -75,7 +63,6 @@ static struct option longopts[] =
 };
 
 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
-static void load_state_number(void);
 
 #ifdef SIMULATIONS
 extern void simulator (int, char **);
@@ -88,11 +75,8 @@ extern void simulator (int, char **);
 static void 
 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
 {
-       struct sockaddr_in *sin = nfs_getrpccaller_in(transp);
-
        /* remote host authorization check */
-       if (sin->sin_family == AF_INET &&
-           !check_default("statd", sin, rqstp->rq_proc, SM_PROG)) {
+       if (!check_default("statd", nfs_getrpccaller(transp), SM_PROG)) {
                svcerr_auth (transp, AUTH_FAILED);
                return;
        }
@@ -103,23 +87,26 @@ sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
 #define sm_prog_1 sm_prog_1_wrapper
 #endif
 
+static void
+statd_unregister(void) {
+       nfs_svc_unregister(SM_PROG, SM_VERS);
+}
+
 /*
  * Signal handler.
  */
 static void 
 killer (int sig)
 {
-       note (N_FATAL, "Caught signal %d, un-registering and exiting.", sig);
-       pmap_unset (SM_PROG, SM_VERS);
-
-       exit (0);
+       statd_unregister ();
+       xlog_err ("Caught signal %d, un-registering and exiting", sig);
 }
 
 static void
 sigusr (int sig)
 {
        extern void my_svc_exit (void);
-       dprintf (N_DEBUG, "Caught signal %d, re-notifying (state %d).", sig,
+       xlog(D_GENERAL, "Caught signal %d, re-notifying (state %d)", sig,
                                                                MY_STATE);
        my_svc_exit();
 }
@@ -140,8 +127,11 @@ static void log_modes(void)
                strcat(buf,"No-Daemon ");
        if (run_mode & MODE_LOG_STDERR)
                strcat(buf,"Log-STDERR ");
+#ifdef HAVE_LIBTIRPC
+       strcat(buf, "TI-RPC ");
+#endif
 
-       note(N_WARNING,buf);
+       xlog_warn(buf);
 }
 
 /*
@@ -175,13 +165,12 @@ static void create_pidfile(void)
        unlink(pidfile);
        fp = fopen(pidfile, "w");
        if (!fp)
-               die("Opening %s failed: %s\n",
-                   pidfile, strerror(errno));
+               xlog_err("Opening %s failed: %m\n", pidfile);
        fprintf(fp, "%d\n", getpid());
        pidfd = dup(fileno(fp));
        if (fclose(fp) < 0) {
-               note(N_WARNING, "Flushing pid file failed: errno %d (%s)\n",
-                       errno, strerror(errno));
+               xlog_warn("Flushing pid file failed: errno %d (%m)\n",
+                       errno);
        }
 }
 
@@ -189,42 +178,10 @@ static void truncate_pidfile(void)
 {
        if (pidfd >= 0) {
                if (ftruncate(pidfd, 0) < 0) {
-                       note(N_WARNING, "truncating pid file failed: errno %d (%s)\n",
-                               errno, strerror(errno));
-               }
-       }
-}
-
-static void drop_privs(void)
-{
-       struct stat st;
-
-       if (stat(SM_DIR, &st) == -1 &&
-           stat(DIR_BASE, &st) == -1) {
-               st.st_uid = 0;
-               st.st_gid = 0;
-       }
-
-       if (st.st_uid == 0) {
-               note(N_WARNING, "statd running as root. chown %s to choose different user\n",
-                   SM_DIR);
-               return;
-       }
-       /* better chown the pid file before dropping, as if it
-        * if over nfs we might loose access
-        */
-       if (pidfd >= 0) {
-               if (fchown(pidfd, st.st_uid, st.st_gid) < 0) {
-                       note(N_ERROR, "Unable to change owner of %s: %d (%s)",
-                                       SM_DIR, strerror (errno));
+                       xlog_warn("truncating pid file failed: errno %d (%m)\n",
+                               errno);
                }
        }
-       setgroups(0, NULL);
-       if (setgid(st.st_gid) == -1
-           || setuid(st.st_uid) == -1) {
-               note(N_ERROR, "Fail to drop privileges");
-               exit(1);
-       }
 }
 
 static void run_sm_notify(int outport)
@@ -266,6 +223,8 @@ int main (int argc, char **argv)
 
        /* Default: daemon mode, no other options */
        run_mode = 0;
+       xlog_stderr(0);
+       xlog_syslog(1);
 
        /* Set the basename */
        if ((name_p = strrchr(argv[0],'/')) != NULL) {
@@ -274,13 +233,6 @@ int main (int argc, char **argv)
                name_p = argv[0];
        }
 
-       /* Get the version */
-       if ((version_p = strrchr(VERSION,' ')) != NULL) {
-               version_p++;
-       } else {
-               version_p = VERSION;
-       }
-       
        /* Set hostname */
        MY_NAME = NULL;
 
@@ -289,7 +241,7 @@ int main (int argc, char **argv)
                switch (arg) {
                case 'V':       /* Version */
                case 'v':
-                       printf("%s version %s\n",name_p,version_p);
+                       printf("%s version " VERSION "\n",name_p);
                        exit(0);
                case 'F':       /* Foreground/nodaemon mode */
                        run_mode |= MODE_NODAEMON;
@@ -326,34 +278,8 @@ int main (int argc, char **argv)
                        MY_NAME = xstrdup(optarg);
                        break;
                case 'P':
-
-                       if ((DIR_BASE = xstrdup(optarg)) == NULL) {
-                               fprintf(stderr, "%s: xstrdup(%s) failed!\n",
-                                       argv[0], optarg);
-                               exit(1);
-                       }
-
-                       SM_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm"));
-                       SM_BAK_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm.bak"));
-                       SM_STAT_PATH = xmalloc(strlen(DIR_BASE) + 1 + sizeof("state"));
-
-                       if ((SM_DIR == NULL) 
-                           || (SM_BAK_DIR == NULL) 
-                           || (SM_STAT_PATH == NULL)) {
-
-                               fprintf(stderr, "%s: xmalloc() failed!\n",
-                                       argv[0]);
+                       if (!nsm_setup_pathnames(argv[0], optarg))
                                exit(1);
-                       }
-                       if (DIR_BASE[strlen(DIR_BASE)-1] == '/') {
-                               sprintf(SM_DIR, "%ssm", DIR_BASE );
-                               sprintf(SM_BAK_DIR, "%ssm.bak", DIR_BASE );
-                               sprintf(SM_STAT_PATH, "%sstate", DIR_BASE );
-                       } else {
-                               sprintf(SM_DIR, "%s/sm", DIR_BASE );
-                               sprintf(SM_BAK_DIR, "%s/sm.bak", DIR_BASE );
-                               sprintf(SM_STAT_PATH, "%s/state", DIR_BASE );
-                       }
                        break;
                case 'H': /* PRC: specify the ha-callout program */
                        if ((ha_callout_prog = xstrdup(optarg)) == NULL) {
@@ -383,7 +309,6 @@ int main (int argc, char **argv)
                run_sm_notify(out_port);
        }
 
-
        if (!(run_mode & MODE_NODAEMON)) {
                run_mode &= ~MODE_LOG_STDERR;   /* Never log to console in
                                                   daemon mode. */
@@ -432,10 +357,6 @@ int main (int argc, char **argv)
                /* Child.       */
                close(pipefds[0]);
                setsid ();
-               if (chdir (DIR_BASE) == -1) {
-                       perror("statd: Could not chdir");
-                       exit(1);
-               }
 
                while (pipefds[1] <= 2) {
                        pipefds[1] = dup(pipefds[1]);
@@ -455,7 +376,13 @@ int main (int argc, char **argv)
 
        /* Child. */
 
-       log_init (/*name_p,version_p*/);
+       if (run_mode & MODE_LOG_STDERR) {
+               xlog_syslog(0);
+               xlog_stderr(1);
+               xlog_config(D_ALL, 1);
+       }
+       xlog_open(name_p);
+       xlog(L_NOTICE, "Version " VERSION " starting");
 
        log_modes();
 
@@ -495,25 +422,48 @@ int main (int argc, char **argv)
         * pass on any SM_NOTIFY that arrives
         */
        load_state();
-       load_state_number();
-       pmap_unset (SM_PROG, SM_VERS);
 
-       /* this registers both UDP and TCP services */
-       rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
+       MY_STATE = nsm_get_state(0);
+       if (MY_STATE == 0)
+               exit(1);
+       xlog(D_GENERAL, "Local NSM state number: %d", MY_STATE);
+       nsm_update_kernel_state(MY_STATE);
+
+       /*
+        * ORDER
+        * Clear old listeners while still root, to override any
+        * permission checking done by rpcbind.
+        */
+       statd_unregister();
+
+       /*
+        * ORDER
+        */
+       if (!nsm_drop_privileges(pidfd))
+               exit(1);
+
+       /*
+        * ORDER
+        * Create RPC listeners after dropping privileges.  This permits
+        * statd to unregister its own listeners when it exits.
+        */
+       if (nfs_svc_create("statd", SM_PROG, SM_VERS, sm_prog_1, port) == 0) {
+               xlog(L_ERROR, "failed to create RPC listeners, exiting");
+               exit(1);
+       }
+       atexit(statd_unregister);
 
        /* If we got this far, we have successfully started, so notify parent */
        if (pipefds[1] > 0) {
                status = 0;
                if (write(pipefds[1], &status, 1) != 1) {
-                       note(N_WARNING, "writing to parent pipe failed: errno %d (%s)\n",
+                       xlog_warn("writing to parent pipe failed: errno %d (%s)\n",
                                errno, strerror(errno));
                }
                close(pipefds[1]);
                pipefds[1] = -1;
        }
 
-       drop_privs();
-
        for (;;) {
                /*
                 * Handle incoming requests:  SM_NOTIFY socket requests, as
@@ -541,29 +491,3 @@ int main (int argc, char **argv)
        }
        return 0;
 }
-
-static void
-load_state_number(void)
-{
-       int fd;
-       const char *file = "/proc/sys/fs/nfs/nsm_local_state";
-
-       if ((fd = open(SM_STAT_PATH, O_RDONLY)) == -1)
-               return;
-
-       if (read(fd, &MY_STATE, sizeof(MY_STATE)) != sizeof(MY_STATE)) {
-               note(N_WARNING, "Unable to read state from '%s': errno %d (%s)",
-                               SM_STAT_PATH, errno, strerror(errno));
-       }
-       close(fd);
-       fd = open(file, O_WRONLY);
-       if (fd >= 0) {
-               char buf[20];
-               snprintf(buf, sizeof(buf), "%d", MY_STATE);
-               if (write(fd, buf, strlen(buf)) != strlen(buf))
-                       note(N_WARNING, "Writing to '%s' failed: errno %d (%s)",
-                               file, errno, strerror(errno));
-               close(fd);
-       }
-
-}
index 88ba2080d76e9fbfe2e56d9a0d18663de017f2eb..e89e666d9cae977e5cad8f07c0144ecb3f6b4d98 100644 (file)
 
 #include "sm_inter.h"
 #include "system.h"
-#include "log.h"
-
-/*
- * Paths and filenames.
- */
-#if defined(NFS_STATEDIR)
-# define DEFAULT_DIR_BASE      NFS_STATEDIR "/"
-#else
-# define DEFAULT_DIR_BASE      "/var/lib/nfs/"
-#endif
-
-#define DEFAULT_SM_DIR         DEFAULT_DIR_BASE "sm"
-#define DEFAULT_SM_BAK_DIR     DEFAULT_DIR_BASE "sm.bak"
-#define DEFAULT_SM_STAT_PATH   DEFAULT_DIR_BASE "state"
-
-/* Added to support run-time specification of state directory path.
- * j_carlos_gomez@yahoo.com
- */
-
-extern char * DIR_BASE;
-extern char *  SM_DIR;
-extern char *  SM_BAK_DIR;
-extern char *  SM_STAT_PATH;
+#include "xlog.h"
 
 /*
  * Status definitions.
@@ -44,7 +22,12 @@ extern char *  SM_STAT_PATH;
 /*
  * Function prototypes.
  */
-extern void    change_state(void);
+extern _Bool   statd_matchhostname(const char *hostname1, const char *hostname2);
+extern _Bool   statd_present_address(const struct sockaddr *sap, char *buf,
+                                       const size_t buflen);
+__attribute_malloc__
+extern char *  statd_canonical_name(const char *hostname);
+
 extern void    my_svc_run(void);
 extern void    notify_hosts(void);
 extern void    shuffle_dirs(void);
@@ -53,7 +36,6 @@ extern int    process_notify_list(void);
 extern int     process_reply(FD_SET_TYPE *);
 extern char *  xstrdup(const char *);
 extern void *  xmalloc(size_t);
-extern void    xunlink (char *, char *);
 extern void    load_state(void);
 
 /*
@@ -84,10 +66,3 @@ extern int run_mode;
  * another host.... */
 #define STATIC_HOSTNAME 8      /* Always use the hostname set by -n */
 #define        MODE_NO_NOTIFY  16      /* Don't notify peers of a reboot */
-/*
- * Program name and version pointers -- See statd.c for the reasoning
- * as to why they're global.
- */
-extern char *name_p;           /* program basename */
-extern const char *version_p;  /* program version */
-
index e8be9f3b4fb12d1035f3898050eb7710c321617b..ffc5e950990c5f7f0b7c1c0b9d06199aed030a41 100644 (file)
-.\"
-.\" statd(8)
+.\"@(#)rpc.statd.8"
 .\"
 .\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de>
 .\" Modified by Jeffrey A. Uphoff, 1999, 2002, 2005.
 .\" Modified by Lon Hohberger, 2000.
 .\" Modified by Paul Clements, 2004.
-.TH rpc.statd 8 "31 Aug 2004"
+.\"
+.\" Rewritten by Chuck Lever <chuck.lever@oracle.com>, 2009.
+.\" Copyright 2009 Oracle.  All rights reserved.
+.\"
+.TH RPC.STATD 8 "1 November 2009
 .SH NAME
-rpc.statd \- NSM status monitor
+rpc.statd \- NSM service daemon
 .SH SYNOPSIS
-.B "rpc.statd [-FNL] [-d] [-?] [-n " name "] [-o " port "] [-p " port "] [-H " prog "] [-V]"
+.BI "rpc.statd [-dh?FLNvVw] [-H " prog "] [-n " my-name "] [-o " outgoing-port "] [-p " listener-port "] [-P " path " ]
 .SH DESCRIPTION
-The
+File locks are not part of persistent file system state.
+Lock state is thus lost when a host reboots.
+.PP
+Network file systems must also detect when lock state is lost
+because a remote host has rebooted.
+After an NFS client reboots, an NFS server must release all file locks
+held by applications that were running on that client.
+After a server reboots, a client must remind the
+server of file locks held by applications running on that client.
+.PP
+For NFS version 2 [RFC1094] and NFS version 3 [RFC1813], the
+.I Network Status Monitor
+protocol (or NSM for short)
+is used to notify NFS peers of reboots.
+On Linux, two separate user-space components constitute the NSM service:
+.TP
 .B rpc.statd
-server implements the NSM (Network Status Monitor) RPC protocol.
-This service is somewhat misnamed, since it doesn't actually provide
-active monitoring as one might suspect; instead, NSM implements a
-reboot notification service. It is used by the NFS file locking service,
-.BR rpc.lockd ,
-to implement lock recovery when the NFS server machine crashes and
-reboots.
-.SS Operation
-For each NFS client or server machine to be monitored,
-.B rpc.statd
-creates a file in
-.BR /var/lib/nfs/sm .
-When starting, it normally runs
+A daemon that listens for reboot notifications from other hosts, and
+manages the list of hosts to be notified when the local system reboots
+.TP
+.B sm-notify
+A helper program that notifies NFS peers after the local system reboots
+.PP
+The local NFS lock manager alerts its local
+.B rpc.statd
+of each remote peer that should be monitored.
+When the local system reboots, the
 .B sm-notify
-to iterate through these files and notify the
-peer
+command notifies the NSM service on monitored peers of the reboot.
+When a remote reboots, that peer notifies the local
+.BR rpc.statd ,
+which in turn passes the reboot notification
+back to the local NFS lock manager.
+.SH NSM OPERATION IN DETAIL
+The first file locking interaction between an NFS client and server causes
+the NFS lock managers on both peers to contact their local NSM service to
+store information about the opposite peer.
+On Linux, the local lock manager contacts
+.BR rpc.statd .
+.PP
+.B rpc.statd
+records information about each monitored NFS peer on persistent storage.
+This information describes how to contact a remote peer
+in case the local system reboots,
+how to recognize which monitored peer is reporting a reboot,
+and how to notify the local lock manager when a monitored peer
+indicates it has rebooted.
+.PP
+An NFS client sends a hostname, known as the client's
+.IR caller_name ,
+in each file lock request.
+An NFS server can use this hostname to send asynchronous GRANT
+calls to a client, or to notify the client it has rebooted.
+.PP
+The Linux NFS server can provide the client's
+.I caller_name
+or the client's network address to
+.BR rpc.statd .
+For the purposes of the NSM protocol,
+this name or address is known as the monitored peer's
+.IR mon_name .
+In addition, the local lock manager tells
 .B rpc.statd
-on those machines.
+what it thinks its own hostname is.
+For the purposes of the NSM protocol,
+this hostname is known as
+.IR my_name .
+.PP
+There is no equivalent interaction between an NFS server and a client
+to inform the client of the server's
+.IR caller_name .
+Therefore NFS clients do not actually know what
+.I mon_name
+an NFS server might use in an SM_NOTIFY request.
+The Linux NFS client uses the server hostname from the mount command
+to identify rebooting NFS servers.
+.SS Reboot notification
+When the local system reboots, the
+.B sm-notify
+command reads the list of monitored peers from persistent storage and
+sends an SM_NOTIFY request to the NSM service on each listed remote peer.
+It uses the
+.I mon_name
+string as the destination.
+To identify which host has rebooted, the
+.B sm-notify
+command normally sends the results of
+.BR gethostname (3)
+as the
+.I my_name
+string.
+The remote
+.B rpc.statd
+matches incoming SM_NOTIFY requests using this string,
+or the caller's network address,
+to one or more peers on its own monitor list.
+.PP
+If
+.B rpc.statd
+does not find a peer on its monitor list that matches
+an incoming SM_NOTIFY request,
+the notification is not forwarded to the local lock manager.
+In addition, each peer has its own
+.IR "NSM state number" ,
+a 32-bit integer that is bumped after each reboot by the
+.B sm-notify
+command.
+.B rpc.statd
+uses this number to distinguish between actual reboots
+and replayed notifications.
+.PP
+Part of NFS lock recovery is rediscovering
+which peers need to be monitored again.
+The
+.B sm-notify
+command clears the monitor list on persistent storage after each reboot.
 .SH OPTIONS
 .TP
-.B -F
-By default,
+.BR -d , " --no-syslog
+Causes
 .B rpc.statd
-forks and puts itself in the background when started. The
-.B -F
-argument tells it to remain in the foreground. This option is
-mainly for debugging purposes.
-.TP
-.B -d
-By default,
-.B rpc.statd
-sends logging messages via
-.BR syslog (3)
-to system log.  The
-.B -d
-argument forces it to log verbose output to
-.B stderr
-instead. This option is mainly for debugging purposes, and may only
-be used in conjunction with the
+to write log messages on
+.I stderr
+instead of to the system log,
+if the
 .B -F
-parameter.
+option was also specified.
 .TP
-.BI "\-n," "" " \-\-name " name 
-specify a name for
-.B rpc.statd
-to use as the local hostname. By default,
-.BR rpc.statd
-will call
-.BR gethostname (2)
-to get the local hostname. Specifying
-a local hostname may be useful for machines with more than one
-interfaces.
+.BR -F , " --foreground
+Keeps
+.B rpc.statd
+attached to its controlling terminal so that NSM
+operation can be monitored directly or run under a debugger.
+If this option is not specified,
+.B rpc.statd
+backgrounds itself soon after it starts.
 .TP
-.BI "\-o," "" " \-\-outgoing\-port "  port
-specify a port for
-.B rpc.statd
-to send outgoing status requests from.  By default,
-.BR rpc.statd
-will ask
-.BR portmap (8)
-to assign it a port number.  As of this writing, there is not
-a standard port number that
-.BR portmap
-always or usually assigns.  Specifying
-a port may be useful when implementing a firewall.
+.BR -h , " -?" , " --help
+Causes
+.B rpc.statd
+to display usage information on
+.I stderr
+and then exit.
 .TP
-.BI "\-p," "" " \-\-port " port
-specify a port for
-.B rpc.statd
-to listen on.  By default,
-.BR rpc.statd
-will ask
-.BR portmap (8)
-to assign it a port number.  As of this writing, there is not
-a standard port number that
-.BR portmap
-always or usually assigns.  Specifying
-a port may be useful when implementing a firewall.
+.BI "\-H," "" " \-\-ha-callout " prog
+Specifies a high availability callout program.
+If this option is not specified, no callouts are performed.
+See the
+.B High-availability callouts
+section below for details.
 .TP
-.BI "\-P," "" " \-\-state\-directory\-path "  directory
-specify a directory in which to place statd state information.
-If this option is not specified the default of 
-.BR /var/lib/nfs
-is used.
+.BR -L , " --no-notify
+Prevents
+.B rpc.statd
+from running the
+.B sm-notify
+command when it starts up,
+preserving the existing NSM state number and monitor list.
+.IP
+Note: the
+.B sm-notify
+command contains a check to ensure it runs only once after each system reboot.
+This prevents spurious reboot notification if
+.B rpc.statd
+restarts without the
+.B -L
+option.
 .TP
-.B -N
-Causes statd to run in the notify-only mode. When started in this mode, the
-statd program will check its state directory, send notifications to any
-monitored nodes, and exit once the notifications have been sent. This mode is
-used to enable Highly Available NFS implementations (i.e. HA-NFS).
-This mode is deprecated \-
+.BI "\-n, " "" "\-\-name " ipaddr " | " hostname
+Specifies the bind address used for RPC listener sockets.
+The
+.I ipaddr
+form can be expressed as either an IPv4 or an IPv6 presentation address.
+If this option is not specified,
+.B rpc.statd
+uses a wildcard address as the transport bind address.
+.IP
+This string is also passed to the
 .B sm-notify
-should be used directly instead.
+command to be used as the source address from which
+to send reboot notification requests.
+See
+.BR sm-notify (8)
+for details.
 .TP
-.BR -L , " --no-notify
-Inhibits the running of
-.BR sm-notify .
-If
+.BR -N
+Causes
+.B rpc.statd
+to run the
 .B sm-notify
-is run by some other script at boot time, there is no need for
-.B statd
-to start sm-notify itself.  This can be appropriate if starting of
-statd needs to be delayed until it is actually need.  In such cases
+command, and then exit.
+Since the
+.B sm-notify
+command can also be run directly, this option is deprecated.
+.TP
+.BI "\-o," "" " \-\-outgoing\-port "  port
+Specifies the source port number the
 .B sm-notify
-should still be run at boot time.
+command should use when sending reboot notifications.
+See
+.BR sm-notify (8)
+for details.
 .TP
-.BI "\-H, " "" " \-\-ha-callout " prog
-Specify a high availability callout program, which will receive callouts
-for all client monitor and unmonitor requests. This allows
+.BI "\-p," "" " \-\-port " port
+Specifies the port number used for RPC listener sockets.
+If this option is not specified,
 .B rpc.statd
-to be used in a High Availability NFS (HA-NFS) environment. The
-program will be run with 3 arguments:  The first is either
-.B add-client
-or
-.B del-client
-depending on the reason for the callout.
-The second will be the name of the client.
-The third will be the name of the server as known to the client.
+chooses a random ephemeral port for each listener socket.
+.IP
+This option can be used to fix the port value of its listeners when
+SM_NOTIFY requests must traverse a firewall between clients and servers.
 .TP
-.B -?
-Causes
+.BI "\-P, " "" \-\-state\-directory\-path " pathname
+Specifies the pathname of the parent directory
+where NSM state information resides.
+If this option is not specified,
 .B rpc.statd
-to print out command-line help and exit.
+uses
+.I /var/lib/nfs
+by default.
+.IP
+After starting,
+.B rpc.statd
+attempts to set its effective UID and GID to the owner
+and group of this directory.
 .TP
-.B -V
+.BR -v ", " -V ", " --version
 Causes
 .B rpc.statd
-to print out version information and exit.
-
-
-
-.SH TCP_WRAPPERS SUPPORT
-This
+to display version information on
+.I stderr
+and then exit.
+.SH SECURITY
+The
 .B rpc.statd
-version is protected by the
+daemon must be started as root to acquire privileges needed
+to create sockets with privileged source ports, and to access the
+state information database.
+Because
+.B rpc.statd
+maintains a long-running network service, however, it drops root privileges
+as soon as it starts up to reduce the risk of a privilege escalation attack.
+.PP
+During normal operation,
+the effective user ID it chooses is the owner of the state directory.
+This allows it to continue to access files in that directory after it
+has dropped its root privileges.
+To control which user ID
+.B rpc.statd
+chooses, simply use
+.BR chown (1)
+to set the owner of
+the state directory.
+.PP
+You can also protect your
+.B rpc.statd
+listeners using the
+.B tcp_wrapper
+library or
+.BR iptables (8).
+To use the
 .B tcp_wrapper
-library. You have to give the clients access to
-.B rpc.statd
-if they should be allowed to use it. To allow connects from clients of
-the .bar.com domain you could use the following line in /etc/hosts.allow:
-
-statd: .bar.com
-
-You have to use the daemon name 
+library, add the hostnames of peers that should be allowed access to
+.IR /etc/hosts.allow .
+Use the daemon name
 .B statd
-for the daemon name (even if the binary has a different name).
-
-For further information please have a look at the
+even if the
+.B rpc.statd
+binary has a different filename.
+.P
+For further information see the
 .BR tcpd (8)
 and
 .BR hosts_access (5)
-manual pages.
-
-.SH SIGNALS
-.BR SIGUSR1
-causes
-.B rpc.statd
-to re-read the notify list from disk
-and send notifications to clients. This can be used in High Availability NFS
-(HA-NFS) environments to notify clients to reacquire file locks upon takeover
-of an NFS export from another server.
-
+man pages.
+.SH ADDITIONAL NOTES
+Lock recovery after a reboot is critical to maintaining data integrity
+and preventing unnecessary application hangs.
+.PP
+To help
+.B rpc.statd
+match SM_NOTIFY requests to NLM requests, a number of best practices
+should be observed, including:
+.IP
+The UTS nodename of your systems should match the DNS names that NFS
+peers use to contact them
+.IP
+The UTS nodenames of your systems should always be fully qualified domain names
+.IP
+The forward and reverse DNS mapping of the UTS nodenames should be
+consistent
+.IP
+The hostname the client uses to mount the server should match the server's
+.I mon_name
+in SM_NOTIFY requests it sends
+.IP
+The use of network addresses as a
+.I mon_name
+or a
+.I my_name
+string should be avoided when
+interoperating with non-Linux NFS implementations.
+.PP
+Unmounting an NFS file system does not necessarily stop
+either the NFS client or server from monitoring each other.
+Both may continue monitoring each other for a time in case subsequent
+NFS traffic between the two results in fresh mounts and additional
+file locking.
+.PP
+On Linux, if the
+.B lockd
+kernel module is unloaded during normal operation,
+all remote NFS peers are unmonitored.
+This can happen on an NFS client, for example,
+if an automounter removes all NFS mount
+points due to inactivity.
+.SS High-availability callouts
+.B rpc.statd
+can exec a special callout program during processing of
+successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests.
+Such a program may be used in High Availability NFS (HA-NFS)
+environments to track lock state that may need to be migrated after
+a system reboot.
+.PP
+The name of the callout program is specified with the
+.B -H
+option.
+The program is run with 3 arguments:
+The first is either
+.B add-client
+or
+.B del-client
+depending on the reason for the callout.
+The second is the
+.I mon_name
+of the monitored peer.
+The third is the
+.I caller_name
+of the requesting lock manager.
+.SS IPv6 and TI-RPC support
+TI-RPC is a pre-requisite for supporting NFS on IPv6.
+If TI-RPC support is built into
+.BR rpc.statd ,
+it attempts to start listeners on network transports marked
+'visible' in
+.IR /etc/netconfig .
+As long as at least one network transport listener starts successfully,
+.B rpc.statd
+will operate.
 .SH FILES
-.BR /var/lib/nfs/state
+.TP 2.5i
+.I /var/lib/nfs/sm
+directory containing monitor list
+.TP 2.5i
+.I /var/lib/nfs/sm.bak
+directory containing notify list
+.TP 2.5i
+.I /var/lib/nfs/state
+NSM state number for this host
+.TP 2.5i
+.I /var/run/run.statd.pid
+pid file
+.TP 2.5i
+.I /etc/netconfig
+network transport capability database
+.SH SEE ALSO
+.BR sm-notify (8),
+.BR nfs (5),
+.BR rpc.nfsd (8),
+.BR rpcbind (8),
+.BR tcpd (8),
+.BR hosts_access (5),
+.BR iptables (8),
+.BR netconfig (5)
+.sp
+RFC 1094 - "NFS: Network File System Protocol Specification"
 .br
-.BR /var/lib/nfs/sm/*
+RFC 1813 - "NFS Version 3 Protocol Specification"
 .br
-.BR /var/lib/nfs/sm.bak/*
-.SH SEE ALSO
-.BR rpc.nfsd(8),
-.BR portmap(8)
+OpenGroup Protocols for Interworking: XNFS, Version 3W - Chapter 11
 .SH AUTHORS
-.br
 Jeff Uphoff <juphoff@users.sourceforge.net>
 .br
 Olaf Kirch <okir@monad.swb.de>
@@ -195,3 +404,5 @@ H.J. Lu <hjl@gnu.org>
 Lon Hohberger <hohberger@missioncriticallinux.com>
 .br
 Paul Clements <paul.clements@steeleye.com>
+.br
+Chuck Lever <chuck.lever@oracle.com>
index 14ee663eed5560b58d8c5d18d4aa9a6fd1477a78..d98ecee45f8dcf8934d6ac84bcbcde839afee3cf 100644 (file)
@@ -101,12 +101,12 @@ my_svc_run(void)
 
                        tv.tv_sec  = NL_WHEN(notify) - now;
                        tv.tv_usec = 0;
-                       dprintf(N_DEBUG, "Waiting for reply... (timeo %d)",
+                       xlog(D_GENERAL, "Waiting for reply... (timeo %d)",
                                                        tv.tv_sec);
                        selret = select(FD_SETSIZE, &readfds,
                                (void *) 0, (void *) 0, &tv);
                } else {
-                       dprintf(N_DEBUG, "Waiting for client connections.");
+                       xlog(D_GENERAL, "Waiting for client connections");
                        selret = select(FD_SETSIZE, &readfds,
                                (void *) 0, (void *) 0, (struct timeval *) 0);
                }
@@ -116,8 +116,7 @@ my_svc_run(void)
                        if (errno == EINTR || errno == ECONNREFUSED
                         || errno == ENETUNREACH || errno == EHOSTUNREACH)
                                continue;
-                       note(N_ERROR, "my_svc_run() - select: %s",
-                               strerror (errno));
+                       xlog(L_ERROR, "my_svc_run() - select: %m");
                        return;
 
                case 0:
diff --git a/utils/statd/version.h b/utils/statd/version.h
deleted file mode 100644 (file)
index 12f16bd..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Copyright (C) 1997-1999 Jeffrey A. Uphoff
- *
- * NSM for Linux.
- */
-
-#define STATD_RELEASE "1.1.1"