]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Merge branch 'upstream'
authorLuk Claes <luk@debian.org>
Sun, 2 Oct 2011 14:47:26 +0000 (16:47 +0200)
committerLuk Claes <luk@debian.org>
Sun, 2 Oct 2011 14:47:26 +0000 (16:47 +0200)
66 files changed:
.gitignore
COPYING
aclocal/keyutils.m4
aclocal/libnfsidmap.m4
aclocal/rpcsec_vers.m4
configure.ac
support/include/nfs/nfs.h
support/include/nfsrpc.h
support/include/rpcmisc.h
support/nfs/exports.c
support/nfs/getport.c
support/nfs/rpc_socket.c
support/nfs/svc_create.c
support/nfs/svc_socket.c
support/nsm/file.c
tests/t0001-statd-basic-mon-unmon.sh
tests/test-lib.sh
tools/mountstats/mountstats.py
tools/nfs-iostat/nfs-iostat.py
tools/nfs-iostat/nfsiostat.man
utils/Makefile.am
utils/blkmapd/Makefile.am [new file with mode: 0644]
utils/blkmapd/blkmapd.man [new file with mode: 0644]
utils/blkmapd/device-discovery.c [new file with mode: 0644]
utils/blkmapd/device-discovery.h [new file with mode: 0644]
utils/blkmapd/device-inq.c [new file with mode: 0644]
utils/blkmapd/device-process.c [new file with mode: 0644]
utils/blkmapd/dm-device.c [new file with mode: 0644]
utils/exportfs/exportfs.c
utils/exportfs/exports.man
utils/gssd/context_lucid.c
utils/gssd/svcgssd_krb5.c
utils/idmapd/idmapd.c
utils/mount/error.c
utils/mount/error.h
utils/mount/fstab.c
utils/mount/fstab.h
utils/mount/mount_libmount.c
utils/mount/network.c
utils/mount/network.h
utils/mount/nfs.man
utils/mount/nfsumount.c
utils/mount/parse_dev.c
utils/mount/parse_dev.h
utils/mount/parse_opt.c
utils/mount/parse_opt.h
utils/mount/stropts.c
utils/mount/stropts.h
utils/mount/token.c
utils/mount/token.h
utils/mount/utils.c
utils/mount/utils.h
utils/mount/version.h
utils/mountd/mountd.c
utils/mountd/mountd.man
utils/nfsd/nfsd.c
utils/nfsd/nfssvc.c
utils/nfsd/nfssvc.h
utils/nfsidmap/nfsidmap.man
utils/statd/COPYRIGHT [deleted file]
utils/statd/hostname.c
utils/statd/monitor.c
utils/statd/rmtcall.c
utils/statd/sm-notify.c
utils/statd/start-statd
utils/statd/statd.man

index aa579b883838dc004e5ae94c2d14c350032b5626..ea08c2ebb10093c7e12110798d5992ecb578ce15 100644 (file)
@@ -36,6 +36,7 @@ support/include/stamp-h1
 lib*.a
 tools/rpcgen/rpcgen
 tools/rpcdebug/rpcdebug
+utils/blkmapd/blkmapd
 utils/exportfs/exportfs
 utils/idmapd/idmapd
 utils/lockd/lockd
diff --git a/COPYING b/COPYING
index 60549be514af76c5db0c17ce6bbe01b2f81e2d9e..941c87de278af88468e104290d62809713ee9ab3 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,12 +1,12 @@
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
-                           Preamble
+                            Preamble
 
   The licenses for most software are designed to take away your
 freedom to share and change it.  By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users.  This
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
+the GNU Lesser General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
 
   The precise terms and conditions for copying, distribution and
 modification follow.
-\f
-                   GNU GENERAL PUBLIC LICENSE
+
+                           GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
   0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
     License.  (Exception: if the Program itself is interactive but
     does not normally print such an announcement, your work based on
     the Program is not required to print an announcement.)
-\f
+
 These requirements apply to the modified work as a whole.  If
 identifiable sections of that work are not derived from the Program,
 and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
 access to copy the source code from the same place counts as
 distribution of the source code, even though third parties are not
 compelled to copy the source along with the object code.
-\f
+
   4. You may not copy, modify, sublicense, or distribute the Program
 except as expressly provided under this License.  Any attempt
 otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
 
 This section is intended to make thoroughly clear what is believed to
 be a consequence of the rest of this License.
-\f
+
   8. If the distribution and/or use of the Program is restricted in
 certain countries either by patents or by copyrighted interfaces, the
 original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@ make exceptions for this.  Our decision will be guided by the two goals
 of preserving the free status of all derivatives of our free software and
 of promoting the sharing and reuse of software generally.
 
-                           NO WARRANTY
+                            NO WARRANTY
 
   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.
 
-                    END OF TERMS AND CONDITIONS
-\f
-           How to Apply These Terms to Your New Programs
+                           END OF TERMS AND CONDITIONS
+
+               How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest
 possible use to the public, the best way to achieve this is to make it
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
 the "copyright" line and a pointer to where the full notice is found.
 
     <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
+    Copyright (C) <year>  <name of author>
 
     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
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
+    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.
 
 Also add information on how to contact you by electronic and paper mail.
 
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
@@ -336,5 +335,5 @@ necessary.  Here is a sample; alter the names:
 This General Public License does not permit incorporating your program into
 proprietary programs.  If your program is a subroutine library, you may
 consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
+library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.
index 84bc112b3ae559da7163f5798ea80eb22a1a89c6..a392c0e99ee12d77f6de225bd460814909351dbc 100644 (file)
@@ -6,6 +6,6 @@ AC_DEFUN([AC_KEYUTILS], [
   AC_CHECK_LIB([keyutils], [keyctl_instantiate], [LIBKEYUTILS=-lkeyutils], ,)
   AC_SUBST(LIBKEYUTILS)
 
-  AC_CHECK_HEADERS([keyutils.h], ,
-                  [AC_MSG_ERROR([keyutils.h header not found.])])
+  AC_CHECK_HEADERS([keyutils.h])
+
 ])dnl
index 4faa923f190c2b14df663ee93697e42b9ecf4b75..484b1ecebfdcb3120464997e5a4b5c900830a260 100644 (file)
@@ -15,7 +15,6 @@ AC_DEFUN([AC_LIBNFSIDMAP], [
                           [Define to 1 if you have the `nfs4_set_debug' function.])])
 
   dnl only enable nfsidmap when libnfsidmap supports it
-  AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [enable_nfsidmap=yes],
-               [enable_nfsidmap=no])
+  AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid])
 
 ])dnl
index 25902ca10ace6ddacb83a9cea156b49400034f00..8218372ceaeef3591a064c5bd906fffade0cd578 100644 (file)
@@ -1,7 +1,7 @@
 dnl Checks librpcsec version
 AC_DEFUN([AC_RPCSEC_VERSION], [
 
-  PKG_CHECK_MODULES([GSSGLUE], [libgssglue >= 0.1])
+  PKG_CHECK_MODULES([GSSGLUE], [libgssglue >= 0.3])
 
   dnl TI-RPC replaces librpcsecgss
   if test "$enable_tirpc" = no; then
index ca12f9ea455231e0c1a43370ff038cfe517c936b..80fb39d3f42e5c89ead0a4f744db9aff509dde20 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.4],[linux-nfs@vger.kernel.org],[nfs-utils])
+AC_INIT([linux nfs-utils],[1.2.5],[linux-nfs@vger.kernel.org],[nfs-utils])
 AC_CANONICAL_BUILD([])
 AC_CANONICAL_HOST([])
 AC_CONFIG_MACRO_DIR(aclocal)
@@ -18,10 +18,19 @@ AC_ARG_WITH(release,
        RELEASE=1)
        AC_SUBST(RELEASE)
 AC_ARG_WITH(statedir,
-       [  --with-statedir=/foo    use state dir /foo [/var/lib/nfs]],
+       [AC_HELP_STRING([--with-statedir=/foo],
+                       [use state dir /foo @<:@default=/var/lib/nfs@:>@])],
        statedir=$withval,
        statedir=/var/lib/nfs)
        AC_SUBST(statedir)
+AC_ARG_WITH(statdpath,
+       [AC_HELP_STRING([--with-statdpath=/foo @<:@default=/var/lib/nfs@:>@],
+               [define statd's state dir as /foo instead of the NFS statedir]
+       )],
+       statdpath=$withval,
+       statdpath=$statedir
+       )
+       AC_SUBST(statdpath)
 AC_ARG_WITH(statduser,
        [AC_HELP_STRING([--with-statduser=rpcuser],
                         [statd to run under @<:@rpcuser or nobody@:>@]
@@ -46,24 +55,12 @@ AC_ARG_WITH(start-statd,
        )
        AC_SUBST(startstatd)
        AC_DEFINE_UNQUOTED(START_STATD, "$startstatd", [Define this to a script which can start statd on mount])
-AC_ARG_ENABLE(nfsv3,
-       [AC_HELP_STRING([--enable-nfsv3],
-                        [enable support for NFSv3 @<:@default=yes@:>@])],
-       enable_nfsv3=$enableval,
-       enable_nfsv3=yes)
-       if test "$enable_nfsv3" = yes; then
-               AC_DEFINE(NFS3_SUPPORTED, 1, [Define this if you want NFSv3 support compiled in])
-       else
-               enable_nfsv3=
-       fi
-       AC_SUBST(enable_nfsv3)
 AC_ARG_ENABLE(nfsv4,
        [AC_HELP_STRING([--enable-nfsv4],
                         [enable support for NFSv4 @<:@default=yes@:>@])],
        enable_nfsv4=$enableval,
        enable_nfsv4=yes)
        if test "$enable_nfsv4" = yes; then
-               AC_DEFINE(NFS4_SUPPORTED, 1, [Define this if you want NFSv4 support compiled in])
                IDMAPD=idmapd
        else
                enable_nfsv4=
@@ -75,13 +72,17 @@ AC_ARG_ENABLE(nfsv4,
 
 AC_ARG_ENABLE(nfsv41,
        [AC_HELP_STRING([--enable-nfsv41],
-                        [enable support for NFSv41 @<:@default=no@:>@])],
+                        [enable support for NFSv41 @<:@default=yes@:>@])],
        enable_nfsv41=$enableval,
-       enable_nfsv41=no)
+       enable_nfsv41=yes)
        if test "$enable_nfsv41" = yes; then
-               AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in])
+               if test "$enable_nfsv4" != yes; then
+                       AC_MSG_ERROR([NFS v4.1 is enabled but NFS v4 is not. Use --disable-nfsv41])
+               fi
+               BLKMAPD=blkmapd
        else
                enable_nfsv41=
+               BLKMAPD=
        fi
        AC_SUBST(enable_nfsv41)
        AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
@@ -92,7 +93,6 @@ AC_ARG_ENABLE(gss,
        enable_gss=$enableval,
        enable_gss=yes)
        if test "$enable_gss" = yes; then
-               AC_DEFINE(GSS_SUPPORTED, 1, [Define this if you want rpcsec_gss support compiled in])
                GSSD=gssd
                SVCGSSD=svcgssd
        else
@@ -114,21 +114,21 @@ AC_ARG_WITH(rpcgen,
        rpcgen_path=$withval,
        rpcgen_path=yes )
        RPCGEN_PATH=
-       if test "$rpcgen_path" == "yes"; then
+       if test "$rpcgen_path" = "yes"; then
            for p in /usr/local/bin/rpcgen /usr/bin/rpcgen /bin/rpcgen
            do if test -f $p ; then RPCGEN_PATH=$p ; break; fi ; done
        elif test "$rpcgen_path" != "internal"; then
            RPCGEN_PATH=$rpcgen_path
        fi
        AC_SUBST(RPCGEN_PATH)
-       AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" == ""])
+       AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = ""])
 AC_ARG_ENABLE(uuid,
        [AC_HELP_STRING([--disable-uuid], [Exclude uuid support to avoid buggy libblkid])],
        if test "$enableval" = "yes" ; then choose_blkid=yes; else choose_blkid=no; fi,
        choose_blkid=default)
 AC_ARG_ENABLE(mount,
        [AC_HELP_STRING([--enable-mount],
-                       [Create mount.nfs and don't use the util-linux mount(8) functionality. @<:@default=yes@:>@])],
+                       [Create mount.nfs and do not use the util-linux mount(8) functionality. @<:@default=yes@:>@])],
        enable_mount=$enableval,
        enable_mount=yes)
        AM_CONDITIONAL(CONFIG_MOUNT, [test "$enable_mount" = "yes"])
@@ -137,7 +137,7 @@ if test "$enable_mount" = yes; then
        AC_ARG_ENABLE(libmount-mount,
                [AC_HELP_STRING([--enable-libmount-mount],
                                [Link mount.nfs with libmount (EXPERIMENTAL)])],
-               enable_libmount=yes,
+               enable_libmount=$enableval,
                enable_libmount=no)
 fi
 
@@ -256,9 +256,6 @@ if test "$enable_nfsv4" = yes; then
   dnl check for nfsidmap libraries and headers
   AC_LIBNFSIDMAP
 
-  dnl enable nfsidmap when its support by libnfsidmap
-  AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$enable_nfsidmap" = "yes"])
-
   dnl check for the keyutils libraries and headers
   AC_KEYUTILS
 
@@ -268,6 +265,9 @@ if test "$enable_nfsv4" = yes; then
     AC_RPCSEC_VERSION
   fi
 fi
+dnl enable nfsidmap when its support by libnfsidmap
+AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"])
+
 
 if test "$knfsd_cv_glibc2" = no; then
     AC_CHECK_LIB(bsd, daemon, [LIBBSD="-lbsd"])
@@ -386,6 +386,7 @@ dnl *************************************************************
 dnl Export some path names to config.h
 dnl *************************************************************
 AC_DEFINE_UNQUOTED(NFS_STATEDIR, "$statedir", [This defines the location of the NFS state files. Warning: this must match definitions in config.mk!])
+AC_DEFINE_UNQUOTED(NSM_DEFAULT_STATEDIR, "$statdpath", [Define this to the pathname where statd keeps its state file])
 
 if test "x$cross_compiling" = "xno"; then
        CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD-"$CFLAGS"}
@@ -450,6 +451,7 @@ AC_CONFIG_FILES([
        tools/mountstats/Makefile
        tools/nfs-iostat/Makefile
        utils/Makefile
+       utils/blkmapd/Makefile
        utils/exportfs/Makefile
        utils/gssd/Makefile
        utils/idmapd/Makefile
index c939d78105b6599857d659b9ba99178e85c98aa4..320880ea7bc9c9f38d2f8a9dfa44ca744ed19c9d 100644 (file)
 #define NFSD_MINVERS 2
 #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;
        u_int8_t        fh_handle[NFS3_FHSIZE];
index d50fe94c8870017f30112af272671cefe62ecdc9..a0b80e15ed5227535ba47e36866d0cfe93648788 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 0b06457bbb74d1d8386fd4c343fd825caa804be8..b806227ecc50acd633ae4d375f6edd1bda6994fc 100644 (file)
@@ -53,6 +53,7 @@ void          rpc_init(char *name, int prog, int vers,
 void           rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
                                struct rpc_dtable *dtable, int nvers,
                                void *argp, void *resp);
+int            getservport(u_long number, const char *proto);
 
 extern int     _rpcpmstart;
 extern int     _rpcfdtype;
index c250383a1b2fe2ada93bc5c8bf172fc02e3ad49b..c96500fdc73a0e09914edf6f4211703d1d84a539 100644 (file)
@@ -784,8 +784,9 @@ struct export_features *get_export_features(void)
        fd = open(path, O_RDONLY);
        if (fd == -1)
                goto good;
-       fd = read(fd, buf, 50);
-       if (fd == -1)
+       c = read(fd, buf, 50);
+       close(fd);
+       if (c == -1)
                goto err;
        c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags);
        if (c != 2)
index d74400b0dcfe69eac02b8dbc2c531d01b16c9d79..3331ad4beda75af72a256a578456c3b3212ef326 100644 (file)
@@ -17,8 +17,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index c14efe8f20ec6fc20397d123f07d1bbe53fd8268..7896cd22678bde2927a3470567973466715150fc 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index b3f75edc2f9608577da0ea5734011d719c827bc5..c159fc8fbb9e0daa8679fc34a82ce19a1105deda 100644 (file)
@@ -393,7 +393,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
        const struct sigaction create_sigaction = {
                .sa_handler     = SIG_IGN,
        };
-       unsigned int visible, up;
+       unsigned int visible, up, servport;
        struct netconfig *nconf;
        void *handlep;
 
@@ -417,8 +417,13 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
                if (!(nconf->nc_flag & NC_VISIBLE))
                        continue;
                visible++;
+               if (port == 0)
+                       servport = getservport(program, nconf->nc_proto);
+               else
+                       servport = port;
+
                up += svc_create_nconf(name, program, version, dispatch,
-                                               port, nconf);
+                                               servport, nconf);
        }
 
        if (visible == 0)
index 03a53256c1f4469ec5a36839672eaa6a5a5f0c28..f56f310fb5c4744ca8a8bcccb5d4ae265b7889c6 100644 (file)
@@ -13,8 +13,8 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 0211-1301 USA */
 
 #include <stdio.h>
 #include <string.h>
 # define __close(f)            close ((f))
 #endif
 
+int getservport(u_long number, const char *proto)
+{
+       char rpcdata[1024], servdata[1024];
+       struct rpcent rpcbuf, *rpcp;
+       struct servent servbuf, *servp = NULL;
+       int ret;
+
+       ret = getrpcbynumber_r(number, &rpcbuf, rpcdata, sizeof rpcdata,
+                               &rpcp);
+       if (ret == 0 && rpcp != NULL) {
+               /* First try name.  */
+               ret = getservbyname_r(rpcp->r_name, proto, &servbuf, servdata,
+                                       sizeof servdata, &servp);
+               if ((ret != 0 || servp == NULL) && rpcp->r_aliases) {
+                       const char **a;
+
+                       /* Then we try aliases.  */
+                       for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) {
+                               ret = getservbyname_r(*a, proto, &servbuf, servdata,
+                                                       sizeof servdata, &servp);
+                               if (ret == 0 && servp != NULL)
+                                       break;
+                       }
+               }
+       }
+
+       if (ret == 0 && servp != NULL)
+               return ntohs(servp->s_port);
+
+       return 0;
+}
+
 static int
 svc_socket (u_long number, int type, int protocol, int reuse)
 {
   struct sockaddr_in addr;
   socklen_t len = sizeof (struct sockaddr_in);
-  char rpcdata [1024], servdata [1024];
-  struct rpcent rpcbuf, *rpcp;
-  struct servent servbuf, *servp = NULL;
   int sock, ret;
   const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
 
@@ -66,48 +95,13 @@ svc_socket (u_long number, int type, int protocol, int reuse)
 
   memset (&addr, 0, sizeof (addr));
   addr.sin_family = AF_INET;
+  addr.sin_port = htons(getservport(number, proto));
 
-  ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
-                         &rpcp);
-  if (ret == 0 && rpcp != NULL)
-    {
-      /* First try name.  */
-      ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
-                            sizeof servdata, &servp);
-      if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
-       {
-         const char **a;
-
-         /* Then we try aliases.  */
-         for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) 
-           {
-             ret = getservbyname_r (*a, proto, &servbuf, servdata,
-                                    sizeof servdata, &servp);
-             if (ret == 0 && servp != NULL)
-               break;
-           }
-       }
-    }
-
-  if (ret == 0 && servp != NULL)
+  if (bind(sock, (struct sockaddr *) &addr, len) < 0)
     {
-      addr.sin_port = servp->s_port;
-      if (bind (sock, (struct sockaddr *) &addr, len) < 0)
-       {
-         perror (_("svc_socket: bind problem"));
-         (void) __close (sock);
-         sock = -1;
-       }
-    }
-  else
-    {
-         addr.sin_port = 0;
-         if (bind (sock, (struct sockaddr *) &addr, len) < 0)
-           {
-             perror (_("svc_socket: bind problem"));
-             (void) __close (sock);
-             sock = -1;
-           }
+      perror (_("svc_socket: bind problem"));
+      (void) __close(sock);
+      sock = -1;
     }
 
   if (sock >= 0)
index 98b47bf8bd9f0b4dae29861b446d7ab3f137d134..5dd52c1e2640fb2effd07004c8902700811aa775 100644 (file)
 
 #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"
@@ -395,18 +387,18 @@ nsm_drop_privileges(const int pidfd)
                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 (st.st_uid == 0) {
+               xlog_warn("Running as root.  "
+                       "chown %s to choose different user", nsm_base_dirname);
+               return true;
+       }
+
        /*
         * If the pidfile happens to reside on NFS, dropping privileges
         * will probably cause us to lose access, even though we are
index 00127fbd3db2c95bec014e640762054ffda8f5ec..51f0d226985bb9f34d8baed68764c6c112e38c3e 100755 (executable)
@@ -16,7 +16,7 @@
 #
 # 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.
+* 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
 #
 
 . ./test-lib.sh
index 3d472649d67ff34603feae67ef6ad64d4876a0fe..ce4ecffd082456188f2d0e3a518fc68738e0348f 100644 (file)
@@ -16,7 +16,7 @@
 #
 # 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.
+* 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
 #
 
 # make sure $srcdir is set and sanity check it
index c475c9efde12bed74abb8205619d2e04d7b46a3a..b95b71d27ef3f43ff9d47bac3753e6b82ad08e90 100644 (file)
@@ -17,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
 """
 
 import sys, os, time
@@ -45,6 +46,12 @@ class DeviceData:
             self.__nfs_data['fstype'] = words[7]
             if words[7].find('nfs') != -1:
                 self.__nfs_data['statvers'] = words[8]
+        elif 'nfs' in words or 'nfs4' in words:
+            self.__nfs_data['export'] = words[0]
+            self.__nfs_data['mountpoint'] = words[3]
+            self.__nfs_data['fstype'] = words[6]
+            if words[6].find('nfs') != -1:
+                self.__nfs_data['statvers'] = words[7]
         elif words[0] == 'age:':
             self.__nfs_data['age'] = long(words[1])
         elif words[0] == 'opts:':
@@ -370,6 +377,9 @@ def parse_stats_file(filename):
         if words[0] == 'device':
             key = words[4]
             new = [ line.strip() ]
+        elif 'nfs' in words or 'nfs4' in words:
+            key = words[3]
+            new = [ line.strip() ]
         else:
             new += [ line.strip() ]
         ms_dict[key] = new
index 1207674e4ad7c19b95fbddfe0de7931708015856..d9096321f59aae9eb131340cb8a5cff5b38d7ccd 100644 (file)
@@ -17,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
 """
 
 import sys, os, time
@@ -85,6 +86,12 @@ class DeviceData:
             self.__nfs_data['fstype'] = words[7]
             if words[7] == 'nfs':
                 self.__nfs_data['statvers'] = words[8]
+        elif 'nfs' in words or 'nfs4' in words:
+            self.__nfs_data['export'] = words[0]
+            self.__nfs_data['mountpoint'] = words[3]
+            self.__nfs_data['fstype'] = words[6]
+            if words[6] == 'nfs':
+                self.__nfs_data['statvers'] = words[7]
         elif words[0] == 'age:':
             self.__nfs_data['age'] = long(words[1])
         elif words[0] == 'opts:':
@@ -425,6 +432,9 @@ def parse_stats_file(filename):
         if words[0] == 'device':
             key = words[4]
             new = [ line.strip() ]
+        elif 'nfs' in words or 'nfs4' in words:
+            key = words[3]
+            new = [ line.strip() ]
         else:
             new += [ line.strip() ]
         ms_dict[key] = new
@@ -435,7 +445,6 @@ def parse_stats_file(filename):
 def print_iostat_summary(old, new, devices, time, options):
     stats = {}
     diff_stats = {}
-
     if old:
         # Trim device list to only include intersection of old and new data,
         # this addresses umounts due to autofs mountpoints
@@ -552,7 +561,6 @@ client are listed.
     parser.add_option_group(displaygroup)
 
     (options, args) = parser.parse_args(sys.argv)
-
     for arg in args:
 
         if arg == sys.argv[0]:
index 99e04fbc2bb3cae44b3dbc9bf9aab0953d505366..3ec245dd07ba737625d3c3773ce323c129444f5a 100644 (file)
@@ -24,7 +24,7 @@ parameter is
 specified, the value of 
 .I <count> 
 determines the number of reports generated at
-. <interval> 
+.I <interval> 
 seconds apart. if the interval parameter is 
 specified without the
 .I <count> 
index a0ea11629a1e6e8bc32a22e7754db1006aff5a69..d074b85b39a95ccbb71479371574b12a9f7d1986 100644 (file)
@@ -9,6 +9,10 @@ OPTDIRS += nfsidmap
 endif
 endif
 
+if CONFIG_NFSV41
+OPTDIRS += blkmapd
+endif
+
 if CONFIG_GSS
 OPTDIRS += gssd
 endif
diff --git a/utils/blkmapd/Makefile.am b/utils/blkmapd/Makefile.am
new file mode 100644 (file)
index 0000000..203f9f2
--- /dev/null
@@ -0,0 +1,19 @@
+## Process this file with automake to produce Makefile.in
+
+man8_MANS      = blkmapd.man
+EXTRA_DIST = $(man8_MANS)
+
+AM_CFLAGS      += -D_LARGEFILE64_SOURCE
+sbin_PROGRAMS  = blkmapd
+
+blkmapd_SOURCES = \
+       device-discovery.c \
+       device-inq.c \
+       device-process.c \
+       dm-device.c \
+       device-discovery.h
+
+blkmapd_LDADD = -ldevmapper ../../support/nfs/libnfs.a
+
+MAINTAINERCLEANFILES = Makefile.in
+
diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man
new file mode 100644 (file)
index 0000000..fd38122
--- /dev/null
@@ -0,0 +1,54 @@
+.\"
+.\" Copyright 2011, Jim Rees.
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the
+.\" nfs-utils distribution.
+.\"
+.TH blkmapd 8 "11 August 2011"
+.SH NAME
+blkmapd \- pNFS block layout mapping daemon
+.SH SYNOPSIS
+.B "blkmapd [-d] [-f]"
+.SH DESCRIPTION
+The
+.B blkmapd
+daemon performs device discovery and mapping for the parallel NFS (pNFS) block layout
+client [RFC5663].
+.PP
+The pNFS block layout protocol builds a complex storage hierarchy from a set
+of
+.I simple volumes.
+These simple volumes are addressed by content, using a signature on the
+volume to uniquely name each one.
+The daemon locates a volume by examining each block device in the system for
+the given signature.
+.PP
+The topology typically consists of a hierarchy of volumes built by striping,
+slicing, and concatenating the simple volumes.
+The
+.B blkmapd
+daemon uses the device-mapper driver to construct logical devices that
+reflect the server topology, and passes these devices to the kernel for use
+by the pNFS block layout client.
+.SH OPTIONS
+.TP
+.B -d
+Performs device discovery only then exits.
+.TP
+.B -f
+Runs
+.B blkmapd
+in the foreground and sends output to stderr (as opposed to syslogd)
+.SH SEE ALSO
+.BR nfs (5),
+.BR dmsetup (8)
+.sp
+RFC 5661 for the NFS version 4.1 specification.
+.br
+RFC 5663 for the pNFS block layout specification.
+.SH AUTHORS
+.br
+Haiying Tang <Tang_Haiying@emc.com>
+.br
+Jim Rees <rees@umich.edu>
diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c
new file mode 100644 (file)
index 0000000..c21de3e
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * device-discovery.c: main function, discovering device and processing
+ * pipe request from kernel.
+ *
+ * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/select.h>
+#include <linux/kdev_t.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <errno.h>
+#include <libdevmapper.h>
+
+#include "device-discovery.h"
+
+#define BL_PIPE_FILE   "/var/lib/nfs/rpc_pipefs/nfs/blocklayout"
+#define PID_FILE       "/var/run/blkmapd.pid"
+
+struct bl_disk *visible_disk_list;
+
+struct bl_disk_path *bl_get_path(const char *filepath,
+                                struct bl_disk_path *paths)
+{
+       struct bl_disk_path *tmp = paths;
+
+       while (tmp) {
+               if (!strcmp(tmp->full_path, filepath))
+                       break;
+               tmp = tmp->next;
+       }
+       return tmp;
+}
+
+/* Check whether valid_path is a substring(partition) of path */
+int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path)
+{
+       if (!strncmp(valid_path->full_path, path->full_path,
+                    strlen(valid_path->full_path)))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * For multipath devices, devices state could be PASSIVE/ACTIVE/PSEUDO,
+ * where PSEUDO > ACTIVE > PASSIVE. Device with highest state is used to
+ * create pseudo device. So if state is higher, the device path needs to
+ * be updated.
+ * If device-mapper multipath support is a must, pseudo devices should
+ * exist for each multipath device. If not, active device path will be
+ * chosen for device creation.
+ * Treat partition as invalid path.
+ */
+int bl_update_path(struct bl_disk_path *path, enum bl_path_state_e state,
+                  struct bl_disk *disk)
+{
+       struct bl_disk_path *valid_path = disk->valid_path;
+
+       if (valid_path) {
+               if (valid_path->state >= state) {
+                       if (bl_is_partition(valid_path, path))
+                               return 0;
+               }
+       }
+       return 1;
+}
+
+void bl_release_disk(void)
+{
+       struct bl_disk *disk;
+       struct bl_disk_path *path = NULL;
+
+       while (visible_disk_list) {
+               disk = visible_disk_list;
+               path = disk->paths;
+               while (path) {
+                       disk->paths = path->next;
+                       free(path->full_path);
+                       free(path);
+                       path = disk->paths;
+               }
+               if (disk->serial)
+                       free(disk->serial);
+               visible_disk_list = disk->next;
+               free(disk);
+       }
+}
+
+void bl_add_disk(char *filepath)
+{
+       struct bl_disk *disk = NULL;
+       int fd = 0;
+       struct stat sb;
+       off_t size = 0;
+       struct bl_serial *serial = NULL;
+       enum bl_path_state_e ap_state;
+       struct bl_disk_path *diskpath = NULL, *path = NULL;
+       dev_t dev;
+
+       fd = open(filepath, O_RDONLY | O_LARGEFILE);
+       if (fd < 0)
+               return;
+
+       if (fstat(fd, &sb)) {
+               close(fd);
+               return;
+       }
+
+       if (!sb.st_size)
+               ioctl(fd, BLKGETSIZE, &size);
+       else
+               size = sb.st_size;
+
+       if (!size) {
+               close(fd);
+               return;
+       }
+
+       dev = sb.st_rdev;
+       serial = bldev_read_serial(fd, filepath);
+       if (dm_is_dm_major(major(dev)))
+               ap_state = BL_PATH_STATE_PSEUDO;
+       else
+               ap_state = bldev_read_ap_state(fd);
+       close(fd);
+
+       if (ap_state != BL_PATH_STATE_ACTIVE)
+               return;
+
+       for (disk = visible_disk_list; disk != NULL; disk = disk->next) {
+               /* Already scanned or a partition?
+                * XXX: if released each time, maybe not need to compare
+                */
+               if ((serial->len == disk->serial->len) &&
+                   !memcmp(serial->data, disk->serial->data, serial->len)) {
+                       diskpath = bl_get_path(filepath, disk->paths);
+                       break;
+               }
+       }
+
+       if (disk && diskpath)
+               return;
+
+       /* add path */
+       path = malloc(sizeof(struct bl_disk_path));
+       if (!path) {
+               BL_LOG_ERR("%s: Out of memory!\n", __func__);
+               goto out_err;
+       }
+       path->next = NULL;
+       path->state = ap_state;
+       path->full_path = strdup(filepath);
+       if (!path->full_path)
+               goto out_err;
+
+       if (!disk) {            /* add disk */
+               disk = malloc(sizeof(struct bl_disk));
+               if (!disk) {
+                       BL_LOG_ERR("%s: Out of memory!\n", __func__);
+                       goto out_err;
+               }
+               disk->next = visible_disk_list;
+               disk->dev = dev;
+               disk->size = size;
+               disk->serial = serial;
+               disk->valid_path = path;
+               disk->paths = path;
+               visible_disk_list = disk;
+       } else {
+               path->next = disk->paths;
+               disk->paths = path;
+               /* check whether we need to update disk info */
+               if (bl_update_path(path, path->state, disk)) {
+                       disk->dev = dev;
+                       disk->size = size;
+                       disk->valid_path = path;
+               }
+       }
+       return;
+
+ out_err:
+       if (path) {
+               if (path->full_path)
+                       free(path->full_path);
+               free(path);
+       }
+       return;
+}
+
+int bl_discover_devices(void)
+{
+       FILE *f;
+       int n;
+       char buf[PATH_MAX], devname[PATH_MAX], fulldevname[PATH_MAX];
+
+       /* release previous list */
+       bl_release_disk();
+
+       /* scan all block devices */
+       f = fopen("/proc/partitions", "r");
+       if (f == NULL)
+               return 0;
+
+       while (1) {
+               if (fgets(buf, sizeof buf, f) == NULL)
+                       break;
+               n = sscanf(buf, "%*d %*d %*d %31s", devname);
+               if (n != 1)
+                       continue;
+               snprintf(fulldevname, sizeof fulldevname, "/sys/block/%s",
+                        devname);
+               if (access(fulldevname, F_OK) < 0)
+                       continue;
+               snprintf(fulldevname, sizeof fulldevname, "/dev/%s", devname);
+               bl_add_disk(fulldevname);
+       }
+
+       fclose(f);
+
+       return 0;
+}
+
+/* process kernel request
+ * return 0: request processed, and no more request waiting;
+ * return 1: request processed, and more requests waiting;
+ * return < 0: error
+ */
+int bl_disk_inquiry_process(int fd)
+{
+       int ret = 0;
+       struct bl_pipemsg_hdr head;
+       char *buf = NULL;
+       uint32_t major, minor;
+       uint16_t buflen;
+       struct bl_dev_msg reply;
+
+       /* read request */
+       if (atomicio(read, fd, &head, sizeof(head)) != sizeof(head)) {
+               /* Note that an error in this or the next read is pretty
+                * catastrophic, as there is no good way to resync into
+                * the pipe's stream.
+                */
+               BL_LOG_ERR("Read pipefs head error!\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       buflen = head.totallen;
+       buf = malloc(buflen);
+       if (!buf) {
+               BL_LOG_ERR("%s: Out of memory!\n", __func__);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (atomicio(read, fd, buf, buflen) != buflen) {
+               BL_LOG_ERR("Read pipefs content error!\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       reply.status = BL_DEVICE_REQUEST_PROC;
+
+       switch (head.type) {
+       case BL_DEVICE_MOUNT:
+               /*
+                * It shouldn't be necessary to discover devices here, since
+                * process_deviceinfo() will re-discover if it can't find
+                * the devices it needs.  But in the case of multipath
+                * devices (ones that appear more than once, for example an
+                * active and a standby LUN), this will re-order them in the
+                * correct priority.
+                */
+               bl_discover_devices();
+               if (!process_deviceinfo(buf, buflen, &major, &minor)) {
+                       reply.status = BL_DEVICE_REQUEST_ERR;
+                       break;
+               }
+               reply.major = major;
+               reply.minor = minor;
+               break;
+       case BL_DEVICE_UMOUNT:
+               if (!dm_device_remove_all((uint64_t *) buf))
+                       reply.status = BL_DEVICE_REQUEST_ERR;
+               break;
+       default:
+               reply.status = BL_DEVICE_REQUEST_ERR;
+               break;
+       }
+
+       /* write to pipefs */
+       if (atomicio((void *)write, fd, &reply, sizeof(reply))
+           != sizeof(reply)) {
+               BL_LOG_ERR("Write pipefs error!\n");
+               ret = -EIO;
+       }
+
+ out:
+       if (buf)
+               free(buf);
+       return ret;
+}
+
+/* TODO: set bl_process_stop to 1 in command */
+unsigned int bl_process_stop;
+
+int bl_run_disk_inquiry_process(int fd)
+{
+       fd_set rset;
+       int ret;
+
+       bl_process_stop = 0;
+
+       for (;;) {
+               if (bl_process_stop)
+                       return 1;
+               FD_ZERO(&rset);
+               FD_SET(fd, &rset);
+               ret = 0;
+               switch (select(fd + 1, &rset, NULL, NULL, NULL)) {
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       else {
+                               ret = -errno;
+                               goto out;
+                       }
+               case 0:
+                       goto out;
+               default:
+                       if (FD_ISSET(fd, &rset))
+                               ret = bl_disk_inquiry_process(fd);
+               }
+       }
+ out:
+       return ret;
+}
+
+/* Daemon */
+int main(int argc, char **argv)
+{
+       int fd, pidfd = -1, opt, dflag = 0, fg = 0, ret = 1;
+       struct stat statbuf;
+       char pidbuf[64];
+
+       while ((opt = getopt(argc, argv, "df")) != -1) {
+               switch (opt) {
+               case 'd':
+                       dflag = 1;
+                       break;
+               case 'f':
+                       fg = 1;
+                       break;
+               }
+       }
+
+       if (fg) {
+               openlog("blkmapd", LOG_PERROR, 0);
+       } else {
+               if (!stat(PID_FILE, &statbuf)) {
+                       fprintf(stderr, "Pid file %s already existed\n", PID_FILE);
+                       exit(1);
+               }
+
+               if (daemon(0, 0) != 0) {
+                       fprintf(stderr, "Daemonize failed\n");
+                       exit(1);
+               }
+
+               openlog("blkmapd", LOG_PID, 0);
+               pidfd = open(PID_FILE, O_WRONLY | O_CREAT, 0644);
+               if (pidfd < 0) {
+                       BL_LOG_ERR("Create pid file %s failed\n", PID_FILE);
+                       exit(1);
+               }
+
+               if (lockf(pidfd, F_TLOCK, 0) < 0) {
+                       BL_LOG_ERR("Lock pid file %s failed\n", PID_FILE);
+                       close(pidfd);
+                       exit(1);
+               }
+               ftruncate(pidfd, 0);
+               sprintf(pidbuf, "%d\n", getpid());
+               write(pidfd, pidbuf, strlen(pidbuf));
+       }
+
+       if (dflag) {
+               bl_discover_devices();
+               exit(0);
+       }
+
+       /* open pipe file */
+       fd = open(BL_PIPE_FILE, O_RDWR);
+       if (fd < 0) {
+               BL_LOG_ERR("open pipe file %s error\n", BL_PIPE_FILE);
+               exit(1);
+       }
+
+       while (1) {
+               /* discover device when needed */
+               bl_discover_devices();
+
+               ret = bl_run_disk_inquiry_process(fd);
+               if (ret < 0) {
+                       /* what should we do with process error? */
+                       BL_LOG_ERR("inquiry process return %d\n", ret);
+               }
+       }
+
+       if (pidfd >= 0) {
+               close(pidfd);
+               unlink(PID_FILE);
+       }
+
+       exit(ret);
+}
diff --git a/utils/blkmapd/device-discovery.h b/utils/blkmapd/device-discovery.h
new file mode 100644 (file)
index 0000000..a86eed9
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * bl-device-discovery.h
+ *
+ * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef BL_DEVICE_DISCOVERY_H
+#define BL_DEVICE_DISCOVERY_H
+
+#include <stdint.h>
+
+enum blk_vol_type {
+       BLOCK_VOLUME_SIMPLE = 0,        /* maps to a single LU */
+       BLOCK_VOLUME_SLICE = 1,         /* slice of another volume */
+       BLOCK_VOLUME_CONCAT = 2,        /* concatenation of multiple volumes */
+       BLOCK_VOLUME_STRIPE = 3,        /* striped across multiple volumes */
+       BLOCK_VOLUME_PSEUDO = 4,
+};
+
+/* All disk offset/lengths are stored in 512-byte sectors */
+struct bl_volume {
+       uint32_t bv_type;
+       off_t bv_size;
+       struct bl_volume **bv_vols;
+       int bv_vol_n;
+       union {
+               dev_t bv_dev;           /* for BLOCK_VOLUME_SIMPLE(PSEUDO) */
+               off_t bv_stripe_unit;   /* for BLOCK_VOLUME_STRIPE(CONCAT) */
+               off_t bv_offset;        /* for BLOCK_VOLUME_SLICE */
+       } param;
+};
+
+struct bl_sig_comp {
+       int64_t bs_offset;              /* In bytes */
+       uint32_t bs_length;             /* In bytes */
+       char *bs_string;
+};
+
+/* Maximum number of signatures components in a simple volume */
+# define BLOCK_MAX_SIG_COMP 16
+
+struct bl_sig {
+       int si_num_comps;
+       struct bl_sig_comp si_comps[BLOCK_MAX_SIG_COMP];
+};
+
+/*
+ * Multipath support: ACTIVE or PSEUDO device is valid,
+ *                   PASSIVE is a standby for ACTIVE.
+ */
+enum bl_path_state_e {
+       BL_PATH_STATE_PASSIVE = 1,
+       BL_PATH_STATE_ACTIVE = 2,
+       BL_PATH_STATE_PSEUDO = 3,
+};
+
+struct bl_serial {
+       int len;
+       char *data;
+};
+
+struct bl_disk_path {
+       struct bl_disk_path *next;
+       char *full_path;
+       enum bl_path_state_e state;
+};
+
+struct bl_disk {
+       struct bl_disk *next;
+       struct bl_serial *serial;
+       dev_t dev;
+       off_t size;                     /* in 512-byte sectors */
+       struct bl_disk_path *valid_path;
+       struct bl_disk_path *paths;
+};
+
+struct bl_dev_id {
+       unsigned char type;
+       unsigned char ids;
+       unsigned char reserve;
+       unsigned char len;
+       char data[0];
+};
+
+struct bl_dev_msg {
+       int status;
+       uint32_t major, minor;
+};
+
+struct bl_pipemsg_hdr {
+       uint8_t type;
+       uint16_t totallen;              /* length of message excluding hdr */
+};
+
+#define BL_DEVICE_UMOUNT                0x0    /* Umount--delete devices */
+#define BL_DEVICE_MOUNT                 0x1    /* Mount--create devices */
+#define BL_DEVICE_REQUEST_INIT          0x0    /* Start request */
+#define BL_DEVICE_REQUEST_PROC          0x1    /* User process succeeds */
+#define BL_DEVICE_REQUEST_ERR           0x2    /* User process fails */
+
+uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes);
+
+#define BLK_READBUF(p, e, nbytes)  do { \
+       p = blk_overflow(p, e, nbytes); \
+       if (!p) {\
+               goto out_err;\
+       } \
+} while (0)
+
+#define READ32(x)         (x) = ntohl(*p++)
+
+#define READ64(x)         do {                  \
+       (x) = (uint64_t)ntohl(*p++) << 32;           \
+       (x) |= ntohl(*p++);                     \
+} while (0)
+
+#define READ_SECTOR(x)     do { \
+       READ64(tmp); \
+       if (tmp & 0x1ff) { \
+               goto out_err; \
+       } \
+       (x) = tmp >> 9; \
+} while (0)
+
+extern struct bl_disk *visible_disk_list;
+uint64_t dm_device_create(struct bl_volume *vols, int num_vols);
+int dm_device_remove_all(uint64_t *dev);
+uint64_t process_deviceinfo(const char *dev_addr_buf,
+                           unsigned int dev_addr_len,
+                           uint32_t *major, uint32_t *minor);
+
+extern ssize_t atomicio(ssize_t(*f) (int, void *, size_t),
+                       int fd, void *_s, size_t n);
+extern struct bl_serial *bldev_read_serial(int fd, const char *filename);
+extern enum bl_path_state_e bldev_read_ap_state(int fd);
+extern int bl_discover_devices(void);
+
+#define BL_LOG_INFO(fmt...)            syslog(LOG_INFO, fmt)
+#define BL_LOG_WARNING(fmt...)         syslog(LOG_WARNING, fmt)
+#define BL_LOG_ERR(fmt...)             syslog(LOG_ERR, fmt)
+#define BL_LOG_DEBUG(fmt...)           syslog(LOG_DEBUG, fmt)
+#endif
diff --git a/utils/blkmapd/device-inq.c b/utils/blkmapd/device-inq.c
new file mode 100644 (file)
index 0000000..eabc70c
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * device-inq.c: inquire SCSI device information.
+ *
+ * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
+ * All rights reserved.
+ *
+ * This program refers to "SCSI Primary Commands - 3 (SPC-3)
+ * at http://www.t10.org and sg_inq.c in sg3_utils-1.26 for
+ * Linux OS SCSI subsystem, by D. Gilbert.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/select.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <errno.h>
+
+#include "device-discovery.h"
+
+#define DEF_ALLOC_LEN  255
+#define MX_ALLOC_LEN   (0xc000 + 0x80)
+
+static struct bl_serial *bl_create_scsi_string(int len, const char *bytes)
+{
+       struct bl_serial *s;
+
+       s = malloc(sizeof(*s) + len);
+       if (s) {
+               s->data = (char *)&s[1];
+               s->len = len;
+               memcpy(s->data, bytes, len);
+       }
+       return s;
+}
+
+static void bl_free_scsi_string(struct bl_serial *str)
+{
+       if (str)
+               free(str);
+}
+
+#define sg_io_ok(io_hdr) \
+       ((((io_hdr).status & 0x7e) == 0) && \
+       ((io_hdr).host_status == 0) && \
+       (((io_hdr).driver_status & 0x0f) == 0))
+
+static int sg_timeout = 1 * 1000;
+
+static int bldev_inquire_page(int fd, int page, char *buffer, int len)
+{
+       unsigned char cmd[] = { INQUIRY, 0, 0, 0, 0, 0 };
+       unsigned char sense_b[28];
+       struct sg_io_hdr io_hdr;
+       if (page >= 0) {
+               cmd[1] = 1;
+               cmd[2] = page;
+       }
+       cmd[3] = (unsigned char)((len >> 8) & 0xff);
+       cmd[4] = (unsigned char)(len & 0xff);
+
+       memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+       io_hdr.interface_id = 'S';
+       io_hdr.cmd_len = sizeof(cmd);
+       io_hdr.mx_sb_len = sizeof(sense_b);
+       io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+       io_hdr.dxfer_len = len;
+       io_hdr.dxferp = buffer;
+       io_hdr.cmdp = cmd;
+       io_hdr.sbp = sense_b;
+       io_hdr.timeout = sg_timeout;
+       if (ioctl(fd, SG_IO, &io_hdr) < 0)
+               return -1;
+
+       if (sg_io_ok(io_hdr))
+               return 0;
+       return -1;
+}
+
+static int bldev_inquire_pages(int fd, int page, char **buffer)
+{
+       int status = 0;
+       char *tmp;
+       int len;
+
+       *buffer = calloc(DEF_ALLOC_LEN, sizeof(char));
+       if (!*buffer) {
+               BL_LOG_ERR("%s: Out of memory!\n", __func__);
+               return -ENOMEM;
+       }
+
+       status = bldev_inquire_page(fd, page, *buffer, DEF_ALLOC_LEN);
+       if (status)
+               goto out;
+
+       status = -1;
+       if ((*(*buffer + 1) & 0xff) != page)
+               goto out;
+
+       len = (*(*buffer + 2) << 8) + *(*buffer + 3) + 4;
+       if (len > MX_ALLOC_LEN) {
+               BL_LOG_ERR("SCSI response length too long: %d\n", len);
+               goto out;
+       }
+       if (len > DEF_ALLOC_LEN) {
+               tmp = realloc(*buffer, len);
+               if (!tmp) {
+                       BL_LOG_ERR("%s: Out of memory!\n", __func__);
+                       status = -ENOMEM;
+                       goto out;
+               }
+               *buffer = tmp;
+               status = bldev_inquire_page(fd, page, *buffer, len);
+               if (status)
+                       goto out;
+       }
+       status = 0;
+ out:
+       return status;
+}
+
+/* For EMC multipath devices, use VPD page (0xc0) to get status.
+ * For other devices, return ACTIVE for now
+ */
+extern enum bl_path_state_e bldev_read_ap_state(int fd)
+{
+       int status = 0;
+       char *buffer = NULL;
+       enum bl_path_state_e ap_state = BL_PATH_STATE_ACTIVE;
+
+       status = bldev_inquire_pages(fd, 0xc0, &buffer);
+       if (status)
+               goto out;
+
+       if (buffer[4] < 0x02)
+               ap_state = BL_PATH_STATE_PASSIVE;
+ out:
+       if (buffer)
+               free(buffer);
+       return ap_state;
+}
+
+struct bl_serial *bldev_read_serial(int fd, const char *filename)
+{
+       struct bl_serial *serial_out = NULL;
+       int status = 0;
+       char *buffer;
+       struct bl_dev_id *dev_root, *dev_id;
+       unsigned int pos, len, current_id = 0;
+
+       status = bldev_inquire_pages(fd, 0x83, &buffer);
+       if (status)
+               goto out;
+
+       dev_root = (struct bl_dev_id *)buffer;
+
+       pos = 0;
+       current_id = 0;
+       len = dev_root->len;
+       while (pos < (len - sizeof(struct bl_dev_id) + sizeof(unsigned char))) {
+               dev_id = (struct bl_dev_id *)&(dev_root->data[pos]);
+               if ((dev_id->ids & 0xf) < current_id)
+                       continue;
+               switch (dev_id->ids & 0xf) {
+                       /* We process SCSI ID with four ID cases: 0, 1, 2 and 3.
+                        * When more than one ID is available, priority is
+                        * 3>2>1>0.
+                        */
+               case 2: /* EUI-64 based */
+                       if ((dev_id->len != 8) && (dev_id->len != 12) &&
+                           (dev_id->len != 16))
+                               break;
+               case 3: /* NAA */
+                       /* TODO: NAA validity judgement too complicated,
+                        * so just ingore it here.
+                        */
+                       if ((dev_id->type & 0xf) != 1) {
+                               BL_LOG_ERR("Binary code_set expected\n");
+                               break;
+                       }
+               case 0: /* vendor specific */
+               case 1: /* T10 vendor identification */
+                       current_id = dev_id->ids & 0xf;
+                       if (serial_out)
+                               bl_free_scsi_string(serial_out);
+                       serial_out = bl_create_scsi_string(dev_id->len,
+                                                          dev_id->data);
+                       break;
+               }
+               if (current_id == 3)
+                       break;
+               pos += (dev_id->len + sizeof(struct bl_dev_id) -
+                       sizeof(unsigned char));
+       }
+ out:
+       if (!serial_out)
+               serial_out = bl_create_scsi_string(strlen(filename), filename);
+       if (buffer)
+               free(buffer);
+       return serial_out;
+}
diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c
new file mode 100644 (file)
index 0000000..27ff374
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * device-process.c: detailed processing of device information sent
+ * from kernel.
+ *
+ * Copyright (c) 2006 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
+ *
+ * Used codes in linux/fs/nfs/blocklayout/blocklayoutdev.c.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <arpa/inet.h>
+#include <linux/kdev_t.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "device-discovery.h"
+
+static char *pretty_sig(char *sig, uint32_t siglen)
+{
+       static char rs[100];
+       uint64_t sigval;
+       unsigned int i;
+
+       if (siglen <= sizeof(sigval)) {
+               sigval = 0;
+               for (i = 0; i < siglen; i++)
+                       sigval |= ((unsigned char *)sig)[i] << (i * 8);
+               sprintf(rs, "0x%0llx", (unsigned long long) sigval);
+       } else {
+               if (siglen > sizeof rs - 4) {
+                       siglen = sizeof rs - 4;
+                       sprintf(&rs[siglen], "...");
+               } else
+                       rs[siglen] = '\0';
+               memcpy(rs, sig, siglen);
+       }
+       return rs;
+}
+
+uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes)
+{
+       uint32_t *q = p + ((nbytes + 3) >> 2);
+
+       if (q > end || q < p)
+               return NULL;
+       return p;
+}
+
+static int decode_blk_signature(uint32_t **pp, uint32_t * end,
+                               struct bl_sig *sig)
+{
+       int i;
+       uint32_t siglen, *p = *pp;
+
+       BLK_READBUF(p, end, 4);
+       READ32(sig->si_num_comps);
+       if (sig->si_num_comps == 0) {
+               BL_LOG_ERR("0 components in sig\n");
+               goto out_err;
+       }
+       if (sig->si_num_comps >= BLOCK_MAX_SIG_COMP) {
+               BL_LOG_ERR("number of sig comps %i >= BLOCK_MAX_SIG_COMP\n",
+                          sig->si_num_comps);
+               goto out_err;
+       }
+       for (i = 0; i < sig->si_num_comps; i++) {
+               struct bl_sig_comp *comp = &sig->si_comps[i];
+
+               BLK_READBUF(p, end, 12);
+               READ64(comp->bs_offset);
+               READ32(siglen);
+               comp->bs_length = siglen;
+               BLK_READBUF(p, end, siglen);
+               /* Note we rely here on fact that sig is used immediately
+                * for mapping, then thrown away.
+                */
+               comp->bs_string = (char *)p;
+               BL_LOG_INFO("%s: si_comps[%d]: bs_length %d, bs_string %s\n",
+                           __func__, i, siglen,
+                           pretty_sig(comp->bs_string, siglen));
+               p += ((siglen + 3) >> 2);
+       }
+       *pp = p;
+       return 0;
+ out_err:
+       return -EIO;
+}
+
+/*
+ * Read signature from device and compare to sig_comp
+ * return: 0=match, 1=no match, -1=error
+ */
+static int
+read_cmp_blk_sig(struct bl_disk *disk, int fd, struct bl_sig_comp *comp)
+{
+       const char *dev_name = disk->valid_path->full_path;
+       int ret = -1;
+       ssize_t siglen = comp->bs_length;
+       int64_t bs_offset = comp->bs_offset;
+       char *sig = NULL;
+
+       sig = (char *)malloc(siglen);
+       if (!sig) {
+               BL_LOG_ERR("%s: Out of memory\n", __func__);
+               goto out;
+       }
+
+       if (bs_offset < 0)
+               bs_offset += (((int64_t) disk->size) << 9);
+       if (lseek64(fd, bs_offset, SEEK_SET) == -1) {
+               BL_LOG_ERR("File %s lseek error\n", dev_name);
+               goto out;
+       }
+
+       if (read(fd, sig, siglen) != siglen) {
+               BL_LOG_ERR("File %s read error\n", dev_name);
+               goto out;
+       }
+
+       ret = memcmp(sig, comp->bs_string, siglen);
+       if (!ret)
+               BL_LOG_INFO("%s: %s sig %s at %lld\n", __func__, dev_name,
+                           pretty_sig(sig, siglen),
+                           (long long)comp->bs_offset);
+
+ out:
+       if (sig)
+               free(sig);
+       return ret;
+}
+
+/*
+ * All signatures in sig must be found on disk for verification.
+ * Returns True if sig matches, False otherwise.
+ */
+static int verify_sig(struct bl_disk *disk, struct bl_sig *sig)
+{
+       const char *dev_name = disk->valid_path->full_path;
+       int fd, i, rv;
+
+       fd = open(dev_name, O_RDONLY | O_LARGEFILE);
+       if (fd < 0) {
+               BL_LOG_ERR("%s: %s could not be opened for read\n", __func__,
+                          dev_name);
+               return 0;
+       }
+
+       rv = 1;
+
+       for (i = 0; i < sig->si_num_comps; i++) {
+               if (read_cmp_blk_sig(disk, fd, &sig->si_comps[i])) {
+                       rv = 0;
+                       break;
+               }
+       }
+
+       if (fd >= 0)
+               close(fd);
+       return rv;
+}
+
+/*
+ * map_sig_to_device()
+ * Given a signature, walk the list of visible disks searching for
+ * a match. Returns True if mapping was done, False otherwise.
+ *
+ * While we're at it, fill in the vol->bv_size.
+ */
+static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol)
+{
+       int mapped = 0;
+       struct bl_disk *disk;
+
+       /* scan disk list to find out match device */
+       for (disk = visible_disk_list; disk; disk = disk->next) {
+               /* FIXME: should we use better algorithm for disk scan? */
+               mapped = verify_sig(disk, sig);
+               if (mapped) {
+                       vol->param.bv_dev = disk->dev;
+                       vol->bv_size = disk->size;
+                       break;
+               }
+       }
+       return mapped;
+}
+
+/* We are given an array of XDR encoded array indices, each of which should
+ * refer to a previously decoded device.  Translate into a list of pointers
+ * to the appropriate pnfs_blk_volume's.
+ */
+static int set_vol_array(uint32_t **pp, uint32_t *end,
+                        struct bl_volume *vols, int working)
+{
+       int i, index;
+       uint32_t *p = *pp;
+       struct bl_volume **array = vols[working].bv_vols;
+
+       for (i = 0; i < vols[working].bv_vol_n; i++) {
+               BLK_READBUF(p, end, 4);
+               READ32(index);
+               if ((index < 0) || (index >= working)) {
+                       BL_LOG_ERR("set_vol_array: Id %i out of range\n",
+                                  index);
+                       goto out_err;
+               }
+               array[i] = &vols[index];
+       }
+       *pp = p;
+       return 0;
+ out_err:
+       return -EIO;
+}
+
+static uint64_t sum_subvolume_sizes(struct bl_volume *vol)
+{
+       int i;
+       uint64_t sum = 0;
+
+       for (i = 0; i < vol->bv_vol_n; i++)
+               sum += vol->bv_vols[i]->bv_size;
+       return sum;
+}
+
+static int
+decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln,
+                 int *array_cnt)
+{
+       int status = 0, j;
+       struct bl_sig sig;
+       uint32_t *p = *pp;
+       struct bl_volume *vol = &vols[voln];
+       uint64_t tmp;
+
+       BLK_READBUF(p, end, 4);
+       READ32(vol->bv_type);
+
+       switch (vol->bv_type) {
+       case BLOCK_VOLUME_SIMPLE:
+               *array_cnt = 0;
+               status = decode_blk_signature(&p, end, &sig);
+               if (status)
+                       return status;
+               status = map_sig_to_device(&sig, vol);
+               if (!status) {
+                       BL_LOG_ERR("Could not find disk for device\n");
+                       return -ENXIO;
+               }
+               BL_LOG_INFO("%s: simple %d\n", __func__, voln);
+               status = 0;
+               break;
+       case BLOCK_VOLUME_SLICE:
+               BLK_READBUF(p, end, 16);
+               READ_SECTOR(vol->param.bv_offset);
+               READ_SECTOR(vol->bv_size);
+               *array_cnt = vol->bv_vol_n = 1;
+               BL_LOG_INFO("%s: slice %d\n", __func__, voln);
+               status = set_vol_array(&p, end, vols, voln);
+               break;
+       case BLOCK_VOLUME_STRIPE:
+               BLK_READBUF(p, end, 8);
+               READ_SECTOR(vol->param.bv_stripe_unit);
+               off_t stripe_unit = vol->param.bv_stripe_unit;
+               /* Check limitations imposed by device-mapper */
+               if ((stripe_unit & (stripe_unit - 1)) != 0
+                   || stripe_unit < (off_t) (PAGE_SIZE >> 9))
+                       return -EIO;
+               BLK_READBUF(p, end, 4);
+               READ32(vol->bv_vol_n);
+               if (!vol->bv_vol_n)
+                       return -EIO;
+               *array_cnt = vol->bv_vol_n;
+               BL_LOG_INFO("%s: stripe %d nvols=%d unit=%ld\n", __func__, voln,
+                           vol->bv_vol_n, (long)stripe_unit);
+               status = set_vol_array(&p, end, vols, voln);
+               if (status)
+                       return status;
+               for (j = 1; j < vol->bv_vol_n; j++) {
+                       if (vol->bv_vols[j]->bv_size !=
+                           vol->bv_vols[0]->bv_size) {
+                               BL_LOG_ERR("varying subvol size\n");
+                               return -EIO;
+                       }
+               }
+               vol->bv_size = vol->bv_vols[0]->bv_size * vol->bv_vol_n;
+               break;
+       case BLOCK_VOLUME_CONCAT:
+               BLK_READBUF(p, end, 4);
+               READ32(vol->bv_vol_n);
+               if (!vol->bv_vol_n)
+                       return -EIO;
+               *array_cnt = vol->bv_vol_n;
+               BL_LOG_INFO("%s: concat %d %d\n", __func__, voln,
+                           vol->bv_vol_n);
+               status = set_vol_array(&p, end, vols, voln);
+               if (status)
+                       return status;
+               vol->bv_size = sum_subvolume_sizes(vol);
+               break;
+       default:
+               BL_LOG_ERR("Unknown volume type %i\n", vol->bv_type);
+ out_err:
+               return -EIO;
+       }
+       *pp = p;
+       return status;
+}
+
+uint64_t process_deviceinfo(const char *dev_addr_buf,
+                           unsigned int dev_addr_len,
+                           uint32_t *major, uint32_t *minor)
+{
+       int num_vols, i, status, count;
+       uint32_t *p, *end;
+       struct bl_volume *vols = NULL, **arrays = NULL, **arrays_ptr = NULL;
+       uint64_t dev = 0;
+
+       p = (uint32_t *) dev_addr_buf;
+       end = (uint32_t *) ((char *)p + dev_addr_len);
+
+       /* Decode block volume */
+       BLK_READBUF(p, end, 4);
+       READ32(num_vols);
+       BL_LOG_INFO("%s: %d vols\n", __func__, num_vols);
+       if (num_vols <= 0)
+               goto out_err;
+
+       vols = (struct bl_volume *)malloc(num_vols * sizeof(struct bl_volume));
+       if (!vols) {
+               BL_LOG_ERR("%s: Out of memory\n", __func__);
+               goto out_err;
+       }
+
+       /* Each volume in vols array needs its own array.  Save time by
+        * allocating them all in one large hunk.  Because each volume
+        * array can only reference previous volumes, and because once
+        * a concat or stripe references a volume, it may never be
+        * referenced again, the volume arrays are guaranteed to fit
+        * in the suprisingly small space allocated.
+        */
+       arrays_ptr = arrays =
+           (struct bl_volume **)malloc(num_vols * 2 *
+                                       sizeof(struct bl_volume *));
+       if (!arrays) {
+               BL_LOG_ERR("%s: Out of memory\n", __func__);
+               goto out_err;
+       }
+
+       for (i = 0; i < num_vols; i++) {
+               vols[i].bv_vols = arrays_ptr;
+               status = decode_blk_volume(&p, end, vols, i, &count);
+               if (status)
+                       goto out_err;
+               arrays_ptr += count;
+       }
+
+       if (p != end) {
+               BL_LOG_ERR("p is not equal to end!\n");
+               goto out_err;
+       }
+
+       dev = dm_device_create(vols, num_vols);
+       if (dev) {
+               *major = MAJOR(dev);
+               *minor = MINOR(dev);
+       }
+
+ out_err:
+       if (vols)
+               free(vols);
+       if (arrays)
+               free(arrays);
+       return dev;
+}
diff --git a/utils/blkmapd/dm-device.c b/utils/blkmapd/dm-device.c
new file mode 100644 (file)
index 0000000..0f4f148
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * dm-device.c: create or remove device via device mapper API.
+ *
+ * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/kdev_t.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <libdevmapper.h>
+
+#include "device-discovery.h"
+
+#define DM_DEV_NAME_LEN                256
+
+#ifndef DM_MAX_TYPE_NAME
+#define DM_MAX_TYPE_NAME       16
+#endif
+
+#define DM_PARAMS_LEN          512     /* XXX: is this enough for target? */
+#define TYPE_HAS_DEV(type)     ((type == BLOCK_VOLUME_SIMPLE) || \
+                        (type == BLOCK_VOLUME_PSEUDO))
+
+struct bl_dm_table {
+       uint64_t offset;
+       uint64_t size;
+       char target_type[DM_MAX_TYPE_NAME];
+       char params[DM_PARAMS_LEN];
+       struct bl_dm_table *next;
+};
+
+struct bl_dm_tree {
+       uint64_t dev;
+       struct dm_tree *tree;
+       struct bl_dm_tree *next;
+};
+
+static const char dm_name[] = "pnfs_vol_%u";
+
+static unsigned int dev_count;
+
+static inline struct bl_dm_table *bl_dm_table_alloc(void)
+{
+       return (struct bl_dm_table *)calloc(1, sizeof(struct bl_dm_table));
+}
+
+static void bl_dm_table_free(struct bl_dm_table *bl_table_head)
+{
+       struct bl_dm_table *p;
+
+       while (bl_table_head) {
+               p = bl_table_head->next;
+               free(bl_table_head);
+               bl_table_head = p;
+       }
+}
+
+static void add_to_bl_dm_table(struct bl_dm_table **bl_table_head,
+                       struct bl_dm_table *table)
+{
+       struct bl_dm_table *p;
+
+       if (!*bl_table_head) {
+               *bl_table_head = table;
+               return;
+       }
+       p = *bl_table_head;
+       while (p->next)
+               p = p->next;
+       p->next = table;
+}
+
+struct bl_dm_tree *bl_tree_head;
+
+static struct bl_dm_tree *find_bl_dm_tree(uint64_t dev)
+{
+       struct bl_dm_tree *p;
+
+       for (p = bl_tree_head; p; p = p->next) {
+               if (p->dev == dev)
+                       break;
+       }
+       return p;
+}
+
+static void del_from_bl_dm_tree(uint64_t dev)
+{
+       struct bl_dm_tree *p, *pre = bl_tree_head;
+
+       for (p = pre; p; p = p->next) {
+               if (p->dev == dev) {
+                       pre->next = p->next;
+                       if (p == bl_tree_head)
+                               bl_tree_head = bl_tree_head->next;
+                       free(p);
+                       break;
+               }
+               pre = p;
+       }
+}
+
+static void add_to_bl_dm_tree(struct bl_dm_tree *tree)
+{
+       struct bl_dm_tree *p;
+
+       if (!bl_tree_head) {
+               bl_tree_head = tree;
+               return;
+       }
+       p = bl_tree_head;
+       while (p->next)
+               p = p->next;
+       p->next = tree;
+       return;
+}
+
+/*
+ * Create device via device mapper
+ * return 0 when creation failed
+ * return dev no for created device
+ */
+static uint64_t
+dm_device_create_mapped(const char *dev_name, struct bl_dm_table *p)
+{
+       struct dm_task *dmt;
+       struct dm_info dminfo;
+       int ret = 0;
+
+       dmt = dm_task_create(DM_DEVICE_CREATE);
+       if (!dmt) {
+               BL_LOG_ERR("Create dm_task for %s failed\n", dev_name);
+               return 0;
+       }
+       ret = dm_task_set_name(dmt, dev_name);
+       if (!ret)
+               goto err_out;
+
+       while (p) {
+               ret =
+                   dm_task_add_target(dmt, p->offset, p->size, p->target_type,
+                                      p->params);
+               if (!ret)
+                       goto err_out;
+               p = p->next;
+       }
+
+       ret = dm_task_run(dmt) && dm_task_get_info(dmt, &dminfo)
+           && dminfo.exists;
+
+       if (!ret)
+               goto err_out;
+
+       dm_task_update_nodes();
+
+ err_out:
+       dm_task_destroy(dmt);
+
+       if (!ret) {
+               BL_LOG_ERR("Create device %s failed\n", dev_name);
+               return 0;
+       }
+       return MKDEV(dminfo.major, dminfo.minor);
+}
+
+static int dm_device_remove_byname(const char *dev_name)
+{
+       struct dm_task *dmt;
+       int ret = 0;
+
+       BL_LOG_INFO("%s: %s\n", __func__, dev_name);
+
+       dmt = dm_task_create(DM_DEVICE_REMOVE);
+       if (!dmt)
+               return 0;
+
+       ret = dm_task_set_name(dmt, dev_name) && dm_task_run(dmt);
+
+       dm_task_update_nodes();
+       dm_task_destroy(dmt);
+
+       return ret;
+}
+
+int dm_device_remove(uint64_t dev)
+{
+       struct dm_task *dmt;
+       struct dm_names *dmnames;
+       char *name = NULL;
+       int ret = 0;
+
+       /* Look for dev_name via dev, if dev_name could be transferred here,
+          we could jump to DM_DEVICE_REMOVE directly */
+
+       dmt = dm_task_create(DM_DEVICE_LIST);
+       if (!dmt) {
+               BL_LOG_ERR("dm_task creation failed\n");
+               goto out;
+       }
+
+       ret = dm_task_run(dmt);
+       if (!ret) {
+               BL_LOG_ERR("dm_task_run failed\n");
+               goto out;
+       }
+
+       dmnames = dm_task_get_names(dmt);
+       if (!dmnames || !dmnames->dev) {
+               BL_LOG_ERR("dm_task_get_names failed\n");
+               goto out;
+       }
+
+       while (dmnames) {
+               if (dmnames->dev == dev) {
+                       name = strdup(dmnames->name);
+                       break;
+               }
+               dmnames = (void *)dmnames + dmnames->next;
+       }
+
+       if (!name) {
+               BL_LOG_ERR("Could not find device\n");
+               goto out;
+       }
+
+       dm_task_update_nodes();
+
+ out:
+       if (dmt)
+               dm_task_destroy(dmt);
+
+       /* Start to remove device */
+       if (name) {
+               ret = dm_device_remove_byname(name);
+               free(name);
+       }
+
+       return ret;
+}
+
+static void dm_devicelist_remove(unsigned int start, unsigned int end)
+{
+       char dev_name[DM_DEV_NAME_LEN];
+       unsigned int count;
+
+       if (start >= dev_count || end <= 1 || start >= end - 1)
+               return;
+
+       for (count = end - 1; count > start; count--) {
+               snprintf(dev_name, sizeof dev_name, dm_name, count - 1);
+               dm_device_remove_byname(dev_name);
+       }
+
+       return;
+}
+
+static void bl_dm_remove_tree(uint64_t dev)
+{
+       struct bl_dm_tree *p;
+
+       p = find_bl_dm_tree(dev);
+       if (!p)
+               return;
+
+       dm_tree_free(p->tree);
+       del_from_bl_dm_tree(dev);
+}
+
+static int bl_dm_create_tree(uint64_t dev)
+{
+       struct dm_tree *tree;
+       struct bl_dm_tree *bl_tree;
+
+       bl_tree = find_bl_dm_tree(dev);
+       if (bl_tree)
+               return 1;
+
+       tree = dm_tree_create();
+       if (!tree)
+               return 0;
+
+       if (!dm_tree_add_dev(tree, MAJOR(dev), MINOR(dev))) {
+               dm_tree_free(tree);
+               return 0;
+       }
+
+       bl_tree = malloc(sizeof(struct bl_dm_tree));
+       if (!bl_tree) {
+               dm_tree_free(tree);
+               return 0;
+       }
+
+       bl_tree->dev = dev;
+       bl_tree->tree = tree;
+       bl_tree->next = NULL;
+       add_to_bl_dm_tree(bl_tree);
+
+       return 1;
+}
+
+int dm_device_remove_all(uint64_t *dev)
+{
+       struct bl_dm_tree *p;
+       struct dm_tree_node *node;
+       const char *uuid;
+       int ret = 0;
+       uint32_t major, minor;
+       uint64_t bl_dev;
+
+       memcpy(&major, dev, sizeof(uint32_t));
+       memcpy(&minor, (void *)dev + sizeof(uint32_t), sizeof(uint32_t));
+       bl_dev = MKDEV(major, minor);
+       p = find_bl_dm_tree(bl_dev);
+       if (!p)
+               return ret;
+
+       node = dm_tree_find_node(p->tree, MAJOR(bl_dev), MINOR(bl_dev));
+       if (!node)
+               return ret;
+
+       uuid = dm_tree_node_get_uuid(node);
+       if (!uuid)
+               return ret;
+
+       dm_device_remove(bl_dev);
+       ret = dm_tree_deactivate_children(node, uuid, strlen(uuid));
+       dm_task_update_nodes();
+       bl_dm_remove_tree(bl_dev);
+
+       return ret;
+}
+
+static int dm_device_exists(char *dev_name)
+{
+       char fullname[DM_DEV_NAME_LEN];
+
+       snprintf(fullname, sizeof fullname, "/dev/mapper/%s", dev_name);
+       return (access(fullname, F_OK) >= 0);
+}
+
+/* TODO: check the value for DM_DEV_NAME_LEN, DM_TYPE_LEN, DM_PARAMS_LEN */
+uint64_t dm_device_create(struct bl_volume *vols, int num_vols)
+{
+       uint64_t size, stripe_unit, dev = 0;
+       unsigned int count = dev_count;
+       int volnum, i, pos;
+       struct bl_volume *node;
+       char *tmp;
+       struct bl_dm_table *table = NULL;
+       struct bl_dm_table *bl_table_head = NULL;
+       unsigned int len;
+       char *dev_name = NULL;
+
+       /* Create pseudo device here */
+       for (volnum = 0; volnum < num_vols; volnum++) {
+               node = &vols[volnum];
+               switch (node->bv_type) {
+               case BLOCK_VOLUME_SIMPLE:
+                       /* Do not need to create device here */
+                       dev = node->param.bv_dev;
+                       goto continued;
+               case BLOCK_VOLUME_SLICE:
+                       table = bl_dm_table_alloc();
+                       if (!table)
+                               goto out;
+                       table->offset = 0;
+                       table->size = node->bv_size;
+                       strcpy(table->target_type, "linear");
+                       if (!TYPE_HAS_DEV(node->bv_vols[0]->bv_type)) {
+                               free(table);
+                               goto out;
+                       }
+                       dev = node->bv_vols[0]->param.bv_dev;
+                       tmp = table->params;
+                       if (!dm_format_dev(tmp, DM_PARAMS_LEN,
+                                          MAJOR(dev), MINOR(dev))) {
+                               free(table);
+                               goto out;
+                       }
+                       tmp += strlen(tmp);
+                       sprintf(tmp, " %lu", node->param.bv_offset);
+                       add_to_bl_dm_table(&bl_table_head, table);
+                       break;
+               case BLOCK_VOLUME_STRIPE:
+                       table = bl_dm_table_alloc();
+                       if (!table)
+                               goto out;
+                       table->offset = 0;
+                       /* Truncate size to a stripe unit boundary */
+                       stripe_unit = node->param.bv_stripe_unit;
+                       table->size =
+                           node->bv_size - (node->bv_size % stripe_unit);
+                       strcpy(table->target_type, "striped");
+                       sprintf(table->params, "%d %llu %n", node->bv_vol_n,
+                               (long long unsigned) stripe_unit, &pos);
+                       /* Copy subdev major:minor to params */
+                       tmp = table->params + pos;
+                       len = DM_PARAMS_LEN - pos;
+                       for (i = 0; i < node->bv_vol_n; i++) {
+                               if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) {
+                                       free(table);
+                                       goto out;
+                               }
+                               dev = node->bv_vols[i]->param.bv_dev;
+                               if (!dm_format_dev(tmp, len, MAJOR(dev),
+                                                  MINOR(dev))) {
+                                       free(table);
+                                       goto out;
+                               }
+                               pos = strlen(tmp);
+                               tmp += pos;
+                               len -= pos;
+                               sprintf(tmp, " %d ", 0);
+                               tmp += 3;
+                               len -= 3;
+                       }
+                       add_to_bl_dm_table(&bl_table_head, table);
+                       break;
+               case BLOCK_VOLUME_CONCAT:
+                       size = 0;
+                       for (i = 0; i < node->bv_vol_n; i++) {
+                               table = bl_dm_table_alloc();
+                               if (!table)
+                                       goto out;
+                               table->offset = size;
+                               table->size = node->bv_vols[i]->bv_size;
+                               if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) {
+                                       free(table);
+                                       goto out;
+                               }
+                               strcpy(table->target_type, "linear");
+                               tmp = table->params;
+                               dev = node->bv_vols[i]->param.bv_dev;
+                               if (!dm_format_dev(tmp, DM_PARAMS_LEN,
+                                                  MAJOR(dev), MINOR(dev))) {
+                                       free(table);
+                                       goto out;
+                               }
+                               tmp += strlen(tmp);
+                               sprintf(tmp, " %d", 0);
+                               size += table->size;
+                               add_to_bl_dm_table(&bl_table_head, table);
+                       }
+                       break;
+               default:
+                       /* Delete previous temporary devices */
+                       dm_devicelist_remove(count, dev_count);
+                       goto out;
+               }               /* end of swtich */
+               /* Create dev_name here. Name of device is pnfs_vol_XXX */
+               if (dev_name)
+                       free(dev_name);
+               dev_name = (char *)calloc(DM_DEV_NAME_LEN, sizeof(char));
+               if (!dev_name) {
+                       BL_LOG_ERR("%s: Out of memory\n", __func__);
+                       goto out;
+               }
+               do {
+                       snprintf(dev_name, DM_DEV_NAME_LEN, dm_name,
+                                dev_count++);
+               } while (dm_device_exists(dev_name));
+
+               dev = dm_device_create_mapped(dev_name, bl_table_head);
+               BL_LOG_INFO("%s: %d %s %d:%d\n", __func__, volnum, dev_name,
+                           (int) MAJOR(dev), (int) MINOR(dev));
+               if (!dev) {
+                       /* Delete previous temporary devices */
+                       dm_devicelist_remove(count, dev_count);
+                       goto out;
+               }
+               node->param.bv_dev = dev;
+               /* TODO: extend use with PSEUDO later */
+               node->bv_type = BLOCK_VOLUME_PSEUDO;
+
+ continued:
+               if (bl_table_head)
+                       bl_dm_table_free(bl_table_head);
+               bl_table_head = NULL;
+       }
+ out:
+       if (bl_table_head) {
+               bl_dm_table_free(bl_table_head);
+               bl_table_head = NULL;
+       }
+       if (dev)
+               bl_dm_create_tree(dev);
+       if (dev_name)
+               free(dev_name);
+       return dev;
+}
index b107c7c9e0d856c1f3678cf4faa70879ce79929f..7432a6592c8d0e69c60dfc69ececec56e92b1f34 100644 (file)
@@ -401,7 +401,7 @@ validate_export(nfs_export *exp)
        int fs_has_fsid = 0;
 
        if (stat(path, &stb) < 0) {
-               xlog(L_ERROR, "Failed to stat %s: %m \n", path);
+               xlog(L_ERROR, "Failed to stat %s: %m", path);
                return;
        }
        if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
@@ -448,6 +448,36 @@ is_hostname(const char *sp)
        return true;
 }
 
+/*
+ * Take care to perform an explicit reverse lookup on presentation
+ * addresses.  Otherwise we don't get a real canonical name or a
+ * complete list of addresses.
+ */
+static struct addrinfo *
+address_list(const char *hostname)
+{
+       struct addrinfo *ai;
+       char *cname;
+
+       ai = host_pton(hostname);
+       if (ai != NULL) {
+               /* @hostname was a presentation address */
+               cname = host_canonname(ai->ai_addr);
+               freeaddrinfo(ai);
+               if (cname != NULL)
+                       goto out;
+       }
+       /* @hostname was a hostname or had no reverse mapping */
+       cname = strdup(hostname);
+       if (cname == NULL)
+               return NULL;
+
+out:
+       ai = host_addrinfo(cname);
+       free(cname);
+       return ai;
+}
+
 static int
 matchhostname(const char *hostname1, const char *hostname2)
 {
@@ -464,10 +494,10 @@ matchhostname(const char *hostname1, const char *hostname2)
        if (!is_hostname(hostname1) || !is_hostname(hostname2))
                return 0;
 
-       results1 = host_addrinfo(hostname1);
+       results1 = address_list(hostname1);
        if (results1 == NULL)
                goto out;
-       results2 = host_addrinfo(hostname2);
+       results2 = address_list(hostname2);
        if (results2 == NULL)
                goto out;
 
@@ -499,9 +529,12 @@ export_d_read(const char *dname)
 
 
        n = scandir(dname, &namelist, NULL, versionsort);
-       if (n < 0)
-               xlog(L_NOTICE, "scandir %s: %s\n", dname, strerror(errno));
-       else if (n == 0)
+       if (n < 0) {
+               if (errno == ENOENT)
+                       /* Silently return */
+                       return;
+               xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno));
+       } else if (n == 0)
                return;
 
        for (i = 0; i < n; i++) {
@@ -528,7 +561,7 @@ export_d_read(const char *dname)
 
                fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name);
                if (fname_len > PATH_MAX) {
-                       xlog(L_WARNING, "Too long file name: %s in %s\n", d->d_name, dname);
+                       xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname);
                        continue;
                }
 
@@ -642,7 +675,7 @@ dump(int verbose)
 static void
 error(nfs_export *exp, int err)
 {
-       xlog(L_ERROR, "%s:%s: %s\n", exp->m_client->m_hostname,
+       xlog(L_ERROR, "%s:%s: %s", exp->m_client->m_hostname,
                exp->m_export.e_path, strerror(err));
 }
 
index b202583ddfae72dc5fa82664a3b12162429bed28..54adfeb555f837f5ba1fd81cf0e2244579674724 100644 (file)
@@ -80,25 +80,25 @@ This is specified by a single
 character (not to be confused with the
 .I wildcard
 entry above) and will match all clients.
-'''.TP
-'''.B =public
-'''This is a special ``hostname'' that identifies the given directory name
-'''as the public root directory (see the section on WebNFS in
-'''.BR nfsd (8)
-'''for a discussion of WebNFS and the public root handle). When using this
-'''convention,
-'''.B =public
-'''must be the only entry on this line, and must have no export options
-'''associated with it. Note that this does
-'''.I not
-'''actually export the named directory; you still have to set the exports
-'''options in a separate entry.
-'''.PP
-'''The public root path can also be specified by invoking
-'''.I nfsd
-'''with the
-'''.B \-\-public\-root
-'''option. Multiple specifications of a public root will be ignored.
+.\".TP
+.\".B =public
+.\"This is a special ``hostname'' that identifies the given directory name
+.\"as the public root directory (see the section on WebNFS in
+.\".BR nfsd (8)
+.\"for a discussion of WebNFS and the public root handle). When using this
+.\"convention,
+.\".B =public
+.\"must be the only entry on this line, and must have no export options
+.\"associated with it. Note that this does
+.\".I not
+.\"actually export the named directory; you still have to set the exports
+.\"options in a separate entry.
+.\".PP
+.\"The public root path can also be specified by invoking
+.\".I nfsd
+.\"with the
+.\".B \-\-public\-root
+.\"option. Multiple specifications of a public root will be ignored.
 .PP
 If a client matches more than one of the specifications above, then
 the first match from the above list order takes precedence - regardless of
@@ -130,7 +130,7 @@ this way are ro, rw, no_root_squash, root_squash, and all_squash.
 .BR exportfs
 understands the following export options:
 .TP
-.IR secure "\*d
+.IR secure
 This option requires that requests originate on an Internet port less
 than IPPORT_RESERVED (1024). This option is on by default. To turn it
 off, specify
@@ -311,24 +311,24 @@ with ACL support (i.e. by default,
 .I no_acl
 is off).
 
-'''.TP
-'''.I noaccess
-'''This makes everything below the directory inaccessible for the named
-'''client.  This is useful when you want to export a directory hierarchy to
-'''a client, but exclude certain subdirectories. The client's view of a
-'''directory flagged with noaccess is very limited; it is allowed to read
-'''its attributes, and lookup `.' and `..'. These are also the only entries
-'''returned by a readdir.
-'''.TP
-'''.IR link_relative
-'''Convert absolute symbolic links (where the link contents start with a
-'''slash) into relative links by prepending the necessary number of ../'s
-'''to get from the directory containing the link to the root on the
-'''server.  This has subtle, perhaps questionable, semantics when the file
-'''hierarchy is not mounted at its root.
-'''.TP
-'''.IR link_absolute
-'''Leave all symbolic link as they are. This is the default operation.
+.\".TP
+.\".I noaccess
+.\"This makes everything below the directory inaccessible for the named
+.\"client.  This is useful when you want to export a directory hierarchy to
+.\"a client, but exclude certain subdirectories. The client's view of a
+.\"directory flagged with noaccess is very limited; it is allowed to read
+.\"its attributes, and lookup `.' and `..'. These are also the only entries
+.\"returned by a readdir.
+.\".TP
+.\".IR link_relative
+.\"Convert absolute symbolic links (where the link contents start with a
+.\"slash) into relative links by prepending the necessary number of ../'s
+.\"to get from the directory containing the link to the root on the
+.\"server.  This has subtle, perhaps questionable, semantics when the file
+.\"hierarchy is not mounted at its root.
+.\".TP
+.\".IR link_absolute
+.\"Leave all symbolic link as they are. This is the default operation.
 
 .TP
 .IR mountpoint= path
@@ -411,21 +411,21 @@ and can be turned off with
 .IR no_root_squash .
 .PP
 By default,
-'''.B nfsd
-'''tries to obtain the anonymous uid and gid by looking up user
-'''.I nobody
-'''in the password file at startup time. If it isn't found, a uid and gid
+.\".B nfsd
+.\"tries to obtain the anonymous uid and gid by looking up user
+.\".I nobody
+.\"in the password file at startup time. If it isn't found, a uid and gid
 .B exportfs
 chooses a uid and gid
 of 65534 for squashed access. These values can also be overridden by
 the
 .IR anonuid " and " anongid
 options.
-'''.PP
-'''In addition to this,
-'''.B nfsd
-'''lets you specify arbitrary uids and gids that should be mapped to user
-'''nobody as well.
+.\".PP
+.\"In addition to this,
+.\".B nfsd
+.\"lets you specify arbitrary uids and gids that should be mapped to user
+.\"nobody as well.
 Finally, you can map all user requests to the
 anonymous uid by specifying the
 .IR all_squash " option.
@@ -490,7 +490,7 @@ The format for extra export tables is the same as
 /srv/www        \-sync,rw server @trusted @external(ro)
 /foo            2001:db8:9:e54::/64(rw) 192.0.2.0/24(rw)
 /build          buildhost[0-9].local.domain(rw)
-'''/pub/private    (noaccess)
+.\"/pub/private    (noaccess)
 .fi
 .PP
 The first line exports the entire filesystem to machines master and trusty.
@@ -508,21 +508,21 @@ as well as the `@trusted' netgroup, and read-only to netgroup `@external',
 all three mounts with the `sync' option enabled. The seventh line exports
 a directory to both an IPv6 and an IPv4 subnet. The eighth line demonstrates
 a character class wildcard match.
-''' The last line denies all NFS clients
-'''access to the private directory.
-'''.SH CAVEATS
-'''Unlike other NFS server implementations, this
-'''.B nfsd
-'''allows you to export both a directory and a subdirectory thereof to
-'''the same host, for instance
-'''.IR /usr " and " /usr/X11R6 .
-'''In this case, the mount options of the most specific entry apply. For
-'''instance, when a user on the client host accesses a file in
-'''.IR /usr/X11R6 ,
-'''the mount options given in the
-'''.I /usr/X11R6
-'''entry apply. This is also true when the latter is a wildcard or netgroup
-'''entry.
+.\" The last line denies all NFS clients
+.\"access to the private directory.
+.\".SH CAVEATS
+.\"Unlike other NFS server implementations, this
+.\".B nfsd
+.\"allows you to export both a directory and a subdirectory thereof to
+.\"the same host, for instance
+.\".IR /usr " and " /usr/X11R6 .
+.\"In this case, the mount options of the most specific entry apply. For
+.\"instance, when a user on the client host accesses a file in
+.\".IR /usr/X11R6 ,
+.\"the mount options given in the
+.\".I /usr/X11R6
+.\"entry apply. This is also true when the latter is a wildcard or netgroup
+.\"entry.
 .SH FILES
 /etc/exports
 /etc/exports.d
@@ -532,17 +532,17 @@ a character class wildcard match.
 .BR mountd (8),
 .BR nfsd (8),
 .BR showmount (8).
-'''.SH DIAGNOSTICS
-'''An error parsing the file is reported using syslogd(8) as level NOTICE from
-'''a DAEMON whenever
-'''.BR nfsd (8)
-'''or
-'''.BR mountd (8)
-'''is started up.  Any unknown
-'''host is reported at that time, but often not all hosts are not yet known
-'''to
-'''.BR named (8)
-'''at boot time, thus as hosts are found they are reported
-'''with the same
-'''.BR syslogd (8)
-'''parameters.
+.\".SH DIAGNOSTICS
+.\"An error parsing the file is reported using syslogd(8) as level NOTICE from
+.\"a DAEMON whenever
+.\".BR nfsd (8)
+.\"or
+.\".BR mountd (8)
+.\"is started up.  Any unknown
+.\"host is reported at that time, but often not all hosts are not yet known
+.\"to
+.\".BR named (8)
+.\"at boot time, thus as hosts are found they are reported
+.\"with the same
+.\".BR syslogd (8)
+.\"parameters.
index b8d4734fe1baa63a93fd019421bf4754053cb7ee..3e695abb8e71dd61f02d2982eeb2dec9a2ffc8a6 100644 (file)
@@ -305,7 +305,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
 
        maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
        if (maj_stat != GSS_S_COMPLETE) {
-               pgsserr("gss_export_lucid_sec_context",
+               pgsserr("gss_free_lucid_sec_context",
                        maj_stat, min_stat, &krb5oid);
                printerr(0, "WARN: failed to free lucid sec context\n");
        }
index fc67a6f1363ded05217725cf1fec415aac094a17..6c34faf4b5f8537fc8c5f04508adf979f2a7ae7e 100644 (file)
@@ -45,6 +45,7 @@
 #include "gss_oids.h"
 #include "err_util.h"
 #include "svcgssd_krb5.h"
+#include "../mount/version.h"
 
 #define MYBUFLEN 1024
 
@@ -169,22 +170,44 @@ svcgssd_limit_krb5_enctypes(void)
 {
 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
        u_int maj_stat, min_stat;
-       krb5_enctype default_enctypes[] = { ENCTYPE_DES_CBC_CRC,
-                                           ENCTYPE_DES_CBC_MD5,
-                                           ENCTYPE_DES_CBC_MD4 };
-       int default_num_enctypes =
-               sizeof(default_enctypes) / sizeof(default_enctypes[0]);
-       krb5_enctype *enctypes;
-       int num_enctypes;
+       krb5_enctype old_kernel_enctypes[] = {
+               ENCTYPE_DES_CBC_CRC,
+               ENCTYPE_DES_CBC_MD5,
+               ENCTYPE_DES_CBC_MD4 };
+       krb5_enctype new_kernel_enctypes[] = {
+               ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+               ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+               ENCTYPE_DES3_CBC_SHA1,
+               ENCTYPE_ARCFOUR_HMAC,
+               ENCTYPE_DES_CBC_CRC,
+               ENCTYPE_DES_CBC_MD5,
+               ENCTYPE_DES_CBC_MD4 };
+       krb5_enctype *default_enctypes, *enctypes;
+       int default_num_enctypes, num_enctypes;
+
+
+       if (linux_version_code() < MAKE_VERSION(2, 6, 35)) {
+               default_enctypes = old_kernel_enctypes;
+               default_num_enctypes =
+                       sizeof(old_kernel_enctypes) / sizeof(old_kernel_enctypes[0]);
+       } else {
+               default_enctypes = new_kernel_enctypes;
+               default_num_enctypes =
+                       sizeof(new_kernel_enctypes) / sizeof(new_kernel_enctypes[0]);
+       }
 
        get_kernel_supported_enctypes();
 
        if (parsed_enctypes != NULL) {
                enctypes = parsed_enctypes;
                num_enctypes = parsed_num_enctypes;
+               printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
+                       "enctypes from the kernel\n", __func__, num_enctypes);
        } else {
                enctypes = default_enctypes;
                num_enctypes = default_num_enctypes;
+               printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
+                       "enctypes from defaults\n", __func__, num_enctypes);
        }
 
        maj_stat = gss_set_allowable_enctypes(&min_stat, gssd_creds,
index 76a56ef6b58f7a8f0d5efa8c7f2f6350f81e3a14..19d91147eaed2a990694a33e683e99e1fcef892c 100644 (file)
@@ -925,9 +925,9 @@ getfield(char **bpp, char *fld, size_t fldsz)
                if (*bp == '\\') {
                        if ((n = sscanf(bp, "\\%03o", &val)) != 1)
                                return (-1);
-                       if (val > (char)-1)
+                       if (val > UCHAR_MAX)
                                return (-1);
-                       *fld++ = (char)val;
+                       *fld++ = val;
                        bp += 4;
                } else {
                        *fld++ = *bp;
index 1b64bd7fb1c9d4267ff88646b5836f4335b4bac4..83ad1d2f796a29551e5beb797966ff17e475c8e9 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  * To Do:
  *  + Proper support for internationalization
index 42b28cf4c05bd2c38e90e468f2d9e7591ee97511..ef80fd079b48ed76aca319060035547736e5ddb5 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 1fc9efe8e24410152c171b5a279c6cbb077565fb..eedbddab87c63e3ea99c2a8507d7028c0d6cc2b5 100644 (file)
@@ -86,10 +86,13 @@ mtab_is_writable() {
 
 struct mntentchn mounttable;
 static int got_mtab = 0;
+struct mntentchn procmounts;
+static int got_procmounts = 0;
 struct mntentchn fstab;
 static int got_fstab = 0;
 
 static void read_mounttable(void);
+static void read_procmounts(void);
 static void read_fstab(void);
 
 static struct mntentchn *
@@ -100,6 +103,14 @@ mtab_head(void)
        return &mounttable;
 }
 
+static struct mntentchn *
+procmounts_head(void)
+{
+       if (!got_procmounts)
+               read_procmounts();
+       return &procmounts;
+}
+
 static struct mntentchn *
 fstab_head(void)
 {
@@ -186,6 +197,30 @@ read_mounttable() {
         read_mntentchn(mfp, fnam, mc);
 }
 
+/*
+ * Read /proc/mounts.
+ * This produces a linked list. The list head procmounts is a dummy.
+ * Return 0 on success.
+ */
+static void
+read_procmounts() {
+        mntFILE *mfp;
+        const char *fnam;
+        struct mntentchn *mc = &procmounts;
+
+        got_procmounts = 1;
+        mc->nxt = mc->prev = NULL;
+
+        fnam = PROC_MOUNTS;
+        mfp = nfs_setmntent(fnam, "r");
+        if (mfp == NULL || mfp->mntent_fp == NULL) {
+                nfs_error(_("warning: can't open %s: %s"),
+                          PROC_MOUNTS, strerror (errno));
+                return;
+        }
+        read_mntentchn(mfp, fnam, mc);
+}
+
 static void
 read_fstab()
 {
@@ -224,6 +259,23 @@ getmntdirbackward (const char *name, struct mntentchn *mcprev) {
        return NULL;
 }
 
+/*
+ * Given the directory name NAME, and the place MCPREV we found it last time,
+ * try to find more occurrences.
+ */
+struct mntentchn *
+getprocmntdirbackward (const char *name, struct mntentchn *mcprev) {
+       struct mntentchn *mc, *mc0;
+
+       mc0 = procmounts_head();
+       if (!mcprev)
+               mcprev = mc0;
+       for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev)
+               if (streq(mc->m.mnt_dir, name))
+                       return mc;
+       return NULL;
+}
+
 /*
  * Given the device name NAME, and the place MCPREV we found it last time,
  * try to find more occurrences.
index dc7c9fc8d73bdc854e78c5c87a68dbb76e71445d..313bf9b3bd9f00d4ae63deb722b341521bcdff89 100644 (file)
@@ -18,6 +18,7 @@ struct mntentchn {
 
 struct mntentchn *getmntoptfile (const char *file);
 struct mntentchn *getmntdirbackward (const char *dir, struct mntentchn *mc);
+struct mntentchn *getprocmntdirbackward (const char *name, struct mntentchn *mc);
 struct mntentchn *getmntdevbackward (const char *dev, struct mntentchn *mc);
 
 struct mntentchn *getfsfile (const char *file);
index 6dd64846470efc9bb3acc55dc0f4a0b598243ae1..e450d798c654924f6a5d3089fc42912f0048f20a 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
@@ -61,10 +61,19 @@ int nomtab;
  * managed by libmount at all. We have to use "mount attributes" that are
  * private for mount.<type> helpers.
  */
-static void store_mount_options(struct libmnt_fs *fs, const char *opts)
+static void store_mount_options(struct libmnt_fs *fs, const char *nfs_opts)
 {
-       mnt_fs_set_fs_options(fs, opts);        /* for mtab */
-       mnt_fs_set_attributes(fs, opts);        /* for non-mtab systems */
+       char *o = NULL;
+
+       mnt_fs_set_attributes(fs, nfs_opts);    /* for non-mtab systems */
+
+       /* for mtab create a new options list */
+       mnt_optstr_append_option(&o, mnt_fs_get_vfs_options(fs), NULL);
+       mnt_optstr_append_option(&o, nfs_opts, NULL);
+       mnt_optstr_append_option(&o, mnt_fs_get_user_options(fs), NULL);
+
+       mnt_fs_set_options(fs, o);
+       free(o);
 }
 
 /*
index d1f91dc0b32c9c501d9253cbe6a576363f7e00f0..e7bd522ac8da7927a7cfde97e3fc968137d356ab 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 81c6f22590eba3e39f152deb79293bc5b705992e..9c75856c9ca898999e650df19e53242fcbe0ad23 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index be91a252150c37dda50610abcff10c7de70d17c4..ce40933b2b42b2d503831c1de43c16d82608c6b6 100644 (file)
@@ -46,11 +46,10 @@ files on this mount point.
 The fifth and sixth fields on each line are not used
 by NFS, thus conventionally each contain the digit zero. For example:
 .P
-.SP
-.NF
-.TA 2.5i +0.75i +0.75i +1.0i
+.nf
+.ta 8n +14n +14n +9n +20n
        server:path     /mountpoint     fstype  option,option,...       0 0
-.FI
+.fi
 .P
 The server's hostname and export pathname
 are separated by a colon, while
@@ -113,12 +112,16 @@ option may mitigate some of the risks of using the
 option.
 .TP 1.5i
 .BI timeo= n
-The time (in tenths of a second) the NFS client waits for a
-response before it retries an NFS request. If this
-option is not specified, requests are retried every
-60 seconds for NFS over TCP.
-The NFS client does not perform any kind of timeout backoff
-for NFS over TCP.
+The time in deciseconds (tenths of a second) the NFS client waits for a
+response before it retries an NFS request.
+.IP
+For NFS over TCP the default
+.B timeo
+value is 600 (60 seconds).
+The NFS client performs linear backoff: After each retransmission the 
+timeout is increased by
+.BR timeo 
+up to the maximum of 600 seconds.
 .IP
 However, for NFS over UDP, the client uses an adaptive
 algorithm to estimate an appropriate timeout value for frequently used
@@ -752,8 +755,8 @@ If
 is specified, the client assumes that POSIX locks are local and uses NLM
 sideband protocol to lock files when flock locks are used.
 .IP
-To support legacy flock behavior similar to that of NFS clients < 2.6.12, use
-'local_lock=flock'. This option is required when exporting NFS mounts via
+To support legacy flock behavior similar to that of NFS clients < 2.6.12, 
+use 'local_lock=flock'. This option is required when exporting NFS mounts via
 Samba as Samba maps Windows share mode locks as flock. Since NFS clients >
 2.6.12 implement flock by emulating POSIX locks, this will result in
 conflicting locks.
@@ -900,40 +903,40 @@ The following example from an
 file causes the mount command to negotiate
 reasonable defaults for NFS behavior.
 .P
-.NF
-.TA 2.5i +0.7i +0.7i +.7i
+.nf
+.ta 8n +16n +6n +6n +30n
        server:/export  /mnt    nfs     defaults        0 0
-.FI
+.fi
 .P
 Here is an example from an /etc/fstab file for an NFS version 2 mount over UDP.
 .P
-.NF
-.TA 2.5i +0.7i +0.7i +.7i
+.nf
+.ta 8n +16n +6n +6n +30n
        server:/export  /mnt    nfs     nfsvers=2,proto=udp     0 0
-.FI
+.fi
 .P
 Try this example to mount using NFS version 4 over TCP
 with Kerberos 5 mutual authentication.
 .P
-.NF
-.TA 2.5i +0.7i +0.7i +.7i
+.nf
+.ta 8n +16n +6n +6n +30n
        server:/export  /mnt    nfs4    sec=krb5        0 0
-.FI
+.fi
 .P
 This example can be used to mount /usr over NFS.
 .P
-.NF
-.TA 2.5i +0.7i +0.7i +.7i
+.nf
+.ta 8n +16n +6n +6n +30n
        server:/export  /usr    nfs     ro,nolock,nocto,actimeo=3600    0 0
-.FI
+.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
+.nf
+.ta 8n +40n +5n +4n +9n
        [fe80::215:c5ff:fb3e:e2b1%eth0]:/export /mnt    nfs     defaults        0 0
-.FI
+.fi
 .SH "TRANSPORT METHODS"
 NFS clients send requests to NFS servers via
 Remote Procedure Calls, or
index 8cd28528b1a01d4c4b86b3306189088b6a927d2a..3538d88036210ee4f00f6ae67b71f3af226c76a8 100644 (file)
@@ -151,65 +151,51 @@ static int del_mtab(const char *spec, const char *node)
  */
 static int nfs_umount_is_vers4(const struct mntentchn *mc)
 {
-       char buffer[LINELEN], *next;
+       struct mntentchn *pmc;
+       struct mount_options *options;
        int retval;
-       FILE *f;
-
-       if ((f = fopen(MOUNTSFILE, "r")) == NULL) {
-               fprintf(stderr, "%s: %s\n",
-                       MOUNTSFILE, strerror(errno));
-               return -1;
-       }
 
        retval = -1;
-       while (fgets(buffer, sizeof(buffer), f) != NULL) {
-               char *device, *mntdir, *type, *flags;
-               struct mount_options *options;
-               char *line = buffer;
-
-               next = strchr(line, '\n');
-               if (next != NULL)
-                       *next = '\0';
-
-               device = strtok(line, " \t");
-               if (device == NULL)
-                       continue;
-               mntdir = strtok(NULL, " \t");
-               if (mntdir == NULL)
-                       continue;
-               if (strcmp(device, mc->m.mnt_fsname) != 0 &&
-                   strcmp(mntdir, mc->m.mnt_dir) != 0)
+       pmc = getprocmntdirbackward(mc->m.mnt_dir, NULL);
+       if (!pmc)
+               goto not_found;
+
+       do {
+               size_t nlen = strlen(pmc->m.mnt_fsname);
+
+               /*
+                * It's possible the mount location string in /proc/mounts
+                * ends with a '/'. In this case, if the entry came from
+                * /etc/mtab, it won't have the trailing '/' so deal with
+                * it.
+                */
+               while (pmc->m.mnt_fsname[nlen - 1] == '/')
+                       nlen--;
+               if (strncmp(pmc->m.mnt_fsname, mc->m.mnt_fsname, nlen) != 0)
                        continue;
 
-               type = strtok(NULL, " \t");
-               if (type == NULL)
-                       continue;
-               if (strcmp(type, "nfs4") == 0)
+               if (strcmp(pmc->m.mnt_type, "nfs4") == 0)
                        goto out_nfs4;
 
-               flags = strtok(NULL, " \t");
-               if (flags == NULL)
-                       continue;
-               options = po_split(flags);
+               options = po_split(pmc->m.mnt_opts);
                if (options != NULL) {
                        unsigned long version;
-                       int rc;
-
-                       rc = nfs_nfs_version(options, &version);
+                       int rc = nfs_nfs_version(options, &version);
                        po_destroy(options);
                        if (rc && version == 4)
                                goto out_nfs4;
                }
 
-               goto out_nfs;
-       }
-       if (retval == -1)
+               if (strcmp(pmc->m.mnt_type, "nfs") == 0)
+                       goto out_nfs;
+       } while ((pmc = getprocmntdirbackward(mc->m.mnt_dir, pmc)) != NULL);
+
+       if (retval == -1) {
+not_found:
                fprintf(stderr, "%s was not found in %s\n",
                        mc->m.mnt_dir, MOUNTSFILE);
-
-out:
-       fclose(f);
-       return retval;
+               goto out;
+       }
 
 out_nfs4:
        if (verbose)
@@ -221,7 +207,9 @@ out_nfs:
        if (verbose)
                fprintf(stderr, "Legacy NFS mount point detected\n");
        retval = 0;
-       goto out;
+
+out:
+       return retval;
 }
 
 static struct option umount_longopts[] =
index c8a58b11f8a4e083e80be7311670b02d5c76de44..d64b83d2ed84621e38d228b23080232bcc223915 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index a1288c20e331e21acd5bac021ec729e5c0321fab..f9857bc3c94ab4a933304d976e3aea0b286b3e05 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index ab869d901d12ba66d0b26b1ac46a23e0d5d90f4e..75a0daaef05f131e15fb2fb6d0499dfee9d3f082 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 2c0b5f4e5b3d1e597c92a563e7adcfb6b8dc9fee..503720727f4bfa8b132c13d60d9117142114f230 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index f1aa5030062e2cb7bee232d6f14ea880ace688b0..314a806799bbe83ed8e805b94059726f152bb898 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
@@ -437,8 +437,8 @@ static int nfs_construct_new_options(struct mount_options *options,
        if (po_append(options, new_option) == PO_FAILED)
                return 0;
 
-       po_remove_all(options, "port");
-       if (nfs_pmap->pm_port != NFS_PORT) {
+       if(po_remove_all(options, "port") == PO_FOUND ||
+          nfs_pmap->pm_port != NFS_PORT) {
                snprintf(new_option, sizeof(new_option) - 1,
                         "port=%lu", nfs_pmap->pm_port);
                if (po_append(options, new_option) == PO_FAILED)
@@ -538,6 +538,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
                errno = ESPIPE;
                if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
                        errno = EOPNOTSUPP;
+               else if (rpc_createerr.cf_stat == RPC_AUTHERROR)
+                       errno = EACCES;
                else if (rpc_createerr.cf_error.re_errno != 0)
                        errno = rpc_createerr.cf_error.re_errno;
                return 0;
index b4fd88878d088e30aa0020c5c975092e648a0006..37316eb6b0ad631c74d1aff6e67dad9b6f7a8314 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 5ef960477698c6625b388cdd754f62b467eaaf6b..d7e2f4a6566e6b3bd207c6e277aa5943c741a38a 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 5a675ed0f62d66ce66c8d61134d4fad241597e5c..17a9c15fe0ba91ae5c76d56a38e9303f5078bd2f 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 298db39a7f8a1e9ed90a905242e835b1cd757db6..2778ed73f43c36106b0404c6ef1fd996eac3d9d6 100644 (file)
@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 3fcd5047cd629538d8a869e8110b761d07ee120e..224918aefd14ee6adf69068653f889a6b97e47f5 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index af61a6f3295996b8d7f160e25fb8e134bbae8751..d7cf68022802a9ea5757641087338f68ea034f61 100644 (file)
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
 #ifndef _NFS_UTILS_MOUNT_VERSION_H
 #define _NFS_UTILS_MOUNT_VERSION_H
 
-#include <stdlib.h>
-#include <string.h>
+#include <stdio.h>
+#include <limits.h>
 
 #include <sys/utsname.h>
 
@@ -37,14 +37,16 @@ static inline unsigned int MAKE_VERSION(unsigned int p, unsigned int q,
 static inline unsigned int linux_version_code(void)
 {
        struct utsname my_utsname;
-       unsigned int p, q, r;
+       unsigned int p, q = 0, r = 0;
 
+       /* UINT_MAX as backward compatibility code should not be run */
        if (uname(&my_utsname))
-               return 0;
+               return UINT_MAX;
 
-       p = (unsigned int)atoi(strtok(my_utsname.release, "."));
-       q = (unsigned int)atoi(strtok(NULL, "."));
-       r = (unsigned int)atoi(strtok(NULL, "."));
+       /* UINT_MAX as future versions might not start with an integer */
+       if (sscanf(my_utsname.release, "%u.%u.%u", &p, &q, &r) < 1)
+               return UINT_MAX;
+       
        return MAKE_VERSION(p, q, r);
 }
 
index 035624c447ccfa68355332802eecdb6eb4069c61..bcf5080a7351b522c436abd24712ae7ff1b43f76 100644 (file)
@@ -633,7 +633,7 @@ 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))
+               if (!strcmp(g->gr_name, newname))
                        return;
 
        g = xmalloc(sizeof(*g));
index 016a357d67e31f9e73f6e726242bca34f902b396..b60dc90fa07e2d9638ae62a9f801e5ba35318961 100644 (file)
@@ -122,7 +122,10 @@ Ignored (compatibility with unfsd??).
 Specifies the port number used for RPC listener sockets.
 If this option is not specified,
 .B rpc.mountd
-chooses a random ephemeral port for each listener socket.
+will try to consult
+.IR /etc/services ,
+if gets port succeed, set the same port for all listener socket,
+otherwise chooses a random ephemeral port for each listener socket.
 .IP
 This option can be used to fix the port value of
 .BR rpc.mountd 's
index e7e1470d3c9ef2a9e20f8f915761d8eac4bf58ea..8bc5d3ad9afc5b962164d188354c8587d29b545c 100644 (file)
@@ -94,7 +94,7 @@ main(int argc, char **argv)
        char *p, *progname, *port;
        char *haddr = NULL;
        int     socket_up = 0;
-       int minorvers4 = NFSD_MAXMINORVERS4;    /* nfsv4 minor version */
+       int minorvers41 = 0;    /* nfsv4 minor version */
        unsigned int versbits = NFSCTL_ALLBITS;
        unsigned int protobits = NFSCTL_ALLBITS;
        unsigned int proto4 = 0;
@@ -154,7 +154,12 @@ main(int argc, char **argv)
                        switch((c = strtol(optarg, &p, 0))) {
                        case 4:
                                if (*p == '.') {
-                                       minorvers4 = -atoi(p + 1);
+                                       int i = atoi(p+1);
+                                       if (i != 1) {
+                                               fprintf(stderr, "%s: unsupported minor version\n", optarg);
+                                               exit(1);
+                                       }
+                                       minorvers41 = -1;
                                        break;
                                }
                        case 3:
@@ -251,7 +256,7 @@ main(int argc, char **argv)
         * registered with rpcbind. Note that on older kernels w/o the right
         * interfaces, these are a no-op.
         */
-       nfssvc_setvers(versbits, minorvers4);
+       nfssvc_setvers(versbits, minorvers41);
  
        error = nfssvc_set_sockets(AF_INET, proto4, haddr, port);
        if (!error)
index f60721450dc7b40054306d9717bff3417f04aa2a..683008e291c6bff1016b365789d3401b5380604c 100644 (file)
@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits,
 }
 
 void
-nfssvc_setvers(unsigned int ctlbits, int minorvers4)
+nfssvc_setvers(unsigned int ctlbits, int minorvers41)
 {
        int fd, n, off;
        char *ptr;
@@ -280,11 +280,9 @@ 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);
+       if (minorvers41)
+               off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1",
+                               minorvers41 > 0 ? '+' : '-');
        for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
                if (NFSCTL_VERISSET(ctlbits, n))
                    off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
index 1a01cec44b5c9fe4784c955f8b76fc87ec2949c7..08de0fe4b90aa1b253e45a43a707f3fcd40f42cd 100644 (file)
@@ -16,7 +16,7 @@
  *
  * 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.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
  *
  */
 
index 6c1a2d474fff900ceb0b8c23e0d7a4c98f0ff2c7..2381908c059ba7840e86f589c456401bd7670b73 100644 (file)
@@ -25,9 +25,9 @@ will need to be modified so
 can properly direct the upcall. The following line should be added before a call
 to keyctl negate:
 .PP
-create nfs_idmap       *       *       /usr/sbin/nfsidmap %k %d 600
+create id_resolver     *       *       /usr/sbin/nfsidmap %k %d 600
 .PP
-This will direct all nfs_idmap requests to the program
+This will direct all id_resolver requests to the program
 .I /usr/sbin/nfsidmap
 The last parameter, 600, defines how many seconds into the future the key will
 expire.  This is an optional parameter for
@@ -48,9 +48,9 @@ You can choose to handle any of these individually, rather than using the
 generic upcall program.  If you would like to use your own program for a uid
 lookup then you would edit your request-key.conf so it looks similar to this:
 .PP
-create nfs_idmap       uid:*   *       /some/other/program %k %d 600
+create id_resolver     uid:*   *       /some/other/program %k %d 600
 .br
-create nfs_idmap       *               *       /usr/sbin/nfsidmap %k %d 600
+create id_resolver     *               *       /usr/sbin/nfsidmap %k %d 600
 .PP
 Notice that the new line was added above the line for the generic program.
 request-key will find the first matching line and run the corresponding program.
diff --git a/utils/statd/COPYRIGHT b/utils/statd/COPYRIGHT
deleted file mode 100644 (file)
index 47ff720..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-rpc.statd -- Network Status Monitor (NSM) protocol daemon for Linux.
-Copyright (C) 1995-1999, 2002, 2005 Jeffrey A. Uphoff
-
-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., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
-
-Jeffrey A. Uphoff
-Orion Multisystems, Inc.
-3090 Oakmead Village Drive
-Santa Clara, CA 95051
-USA
-
-Phone:     +1-408-844-8481
-Internet:  juphoff@users.sourceforge.net
index 616a3cbf45e2668ea57efe69c5aacf6995f80cd5..746ecc7c57b5f6aba93484f4293ab2cc39fa9028 100644 (file)
@@ -225,6 +225,49 @@ statd_canonical_name(const char *hostname)
        return strdup(buf);
 }
 
+/*
+ * Take care to perform an explicit reverse lookup on presentation
+ * addresses.  Otherwise we don't get a real canonical name or a
+ * complete list of addresses.
+ *
+ * Returns an addrinfo list that has ai_canonname filled in, or
+ * NULL if some error occurs.  Caller must free the returned
+ * list with freeaddrinfo(3).
+ */
+__attribute_malloc__
+static struct addrinfo *
+statd_canonical_list(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)
+                       goto out;
+       }
+       /* @hostname was a hostname or had no reverse mapping */
+       strcpy(buf, hostname);
+
+out:
+       hint.ai_flags = AI_CANONNAME;
+       return get_addrinfo(buf, &hint);
+}
+
 /**
  * statd_matchhostname - check if two hostnames are equivalent
  * @hostname1: C string containing hostname
@@ -241,11 +284,6 @@ _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) {
@@ -253,10 +291,10 @@ statd_matchhostname(const char *hostname1, const char *hostname2)
                goto out;
        }
 
-       results1 = get_addrinfo(hostname1, &hint);
+       results1 = statd_canonical_list(hostname1);
        if (results1 == NULL)
                goto out;
-       results2 = get_addrinfo(hostname2, &hint);
+       results2 = statd_canonical_list(hostname2);
        if (results2 == NULL)
                goto out;
 
@@ -276,7 +314,8 @@ out:
        freeaddrinfo(results2);
        freeaddrinfo(results1);
 
-       xlog(D_CALL, "%s: hostnames %s", __func__,
+       xlog(D_CALL, "%s: hostnames %s and %s %s", __func__,
+                       hostname1, hostname2,
                        (result ? "matched" : "did not match"));
        return result;
 }
index 325dfd3ac8bb3c12b7b6ab07b6b97923d46bd615..286a5e21e173442c6445f109ffe82765ea4bfdaf 100644 (file)
@@ -249,7 +249,7 @@ void load_state(void)
 
        count = nsm_load_monitor_list(load_one_host);
        if (count)
-               xlog(D_GENERAL, "Loaded %u previously monitored hosts");
+               xlog(D_GENERAL, "Loaded %u previously monitored hosts", count);
 }
 
 /*
index 0e52fe2b81b1f357637b0e824fe1d4da0cc3827f..4ecb03c25fc9830e25917c8ff39f3ebfb744d579 100644 (file)
@@ -85,7 +85,7 @@ statd_get_socket(void)
 
                memset(&sin, 0, sizeof(sin));
                sin.sin_family = AF_INET;
-               sin.sin_addr.s_addr = INADDR_ANY;
+               sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
                if (bindresvport(sockfd, &sin) < 0) {
                        xlog(D_GENERAL, "%s: can't bind to reserved port",
index 1f490b0e6b7832baadf963f10c5839c846f4e1e9..a3290aa82a84cf5d517212a7c2fa90b2dbb9bc11 100644 (file)
@@ -45,8 +45,9 @@
 struct nsm_host {
        struct nsm_host *       next;
        char *                  name;
-       char *                  mon_name;
-       char *                  my_name;
+       const char *            mon_name;
+       const char *            my_name;
+       char *                  notify_arg;
        struct addrinfo         *ai;
        time_t                  last_used;
        time_t                  send_next;
@@ -93,6 +94,101 @@ smn_lookup(const char *name)
        return ai;
 }
 
+#ifdef HAVE_GETNAMEINFO
+static char *
+smn_get_hostname(const struct sockaddr *sap, const socklen_t salen,
+               const char *name)
+{
+       char buf[NI_MAXHOST];
+       int error;
+
+       error = getnameinfo(sap, salen, buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
+       if (error != 0) {
+               xlog(L_ERROR, "my_name '%s' is unusable: %s",
+                       name, gai_strerror(error));
+               return NULL;
+       }
+       return strdup(buf);
+}
+#else  /* !HAVE_GETNAMEINFO */
+static char *
+smn_get_hostname(const struct sockaddr *sap,
+               __attribute__ ((unused)) const socklen_t salen,
+               const char *name)
+{
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
+       const struct in_addr *addr = &sin->sin_addr;
+       struct hostent *hp;
+
+       if (sap->sa_family != AF_INET) {
+               xlog(L_ERROR, "my_name '%s' is unusable: Bad address family",
+                       name);
+               return NULL;
+       }
+
+       hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
+       if (hp == NULL) {
+               xlog(L_ERROR, "my_name '%s' is unusable: %s",
+                       name, hstrerror(h_errno));
+               return NULL;
+       }
+       return strdup(hp->h_name);
+}
+#endif /* !HAVE_GETNAMEINFO */
+
+/*
+ * Presentation addresses are converted to their canonical hostnames.
+ * If the IP address does not map to a hostname, it is an error:
+ * we never send a presentation address as the argument of SM_NOTIFY.
+ *
+ * If "name" is not a presentation address, it is left alone.  This
+ * allows the administrator some flexibility if DNS isn't configured
+ * exactly how sm-notify prefers it.
+ *
+ * Returns NUL-terminated C string containing the result, or NULL
+ * if the canonical name doesn't exist or cannot be determined.
+ * The caller must free the result with free(3).
+ */
+__attribute_malloc__
+static char *
+smn_verify_my_name(const char *name)
+{
+       struct addrinfo *ai = NULL;
+       struct addrinfo hint = {
+#ifdef IPV6_SUPPORTED
+               .ai_family      = AF_UNSPEC,
+#else  /* !IPV6_SUPPORTED */
+               .ai_family      = AF_INET,
+#endif /* !IPV6_SUPPORTED */
+               .ai_flags       = AI_NUMERICHOST,
+       };
+       char *retval;
+       int error;
+
+       error = getaddrinfo(name, NULL, &hint, &ai);
+       switch (error) {
+       case 0:
+               /* @name was a presentation address */
+               retval = smn_get_hostname(ai->ai_addr, ai->ai_addrlen, name);
+               freeaddrinfo(ai);
+               if (retval == NULL)
+                       return NULL;
+               break;
+       case EAI_NONAME:
+               /* @name was not a presentation address */
+               retval = strdup(name);
+               break;
+       default:
+               xlog(L_ERROR, "my_name '%s' is unusable: %s",
+                       name, gai_strerror(error));
+               return NULL;
+       }
+
+       xlog(D_GENERAL, "Canonical name for my_name '%s': %s",
+                       name, retval);
+       return retval;
+}
+
 __attribute_malloc__
 static struct nsm_host *
 smn_alloc_host(const char *hostname, const char *mon_name,
@@ -104,14 +200,23 @@ smn_alloc_host(const char *hostname, const char *mon_name,
        if (host == NULL)
                goto out_nomem;
 
+       /*
+        * mon_name and my_name are preserved so sm-notify can
+        * find the right monitor record to remove when it is
+        * done processing this host.
+        */
        host->name = strdup(hostname);
-       host->mon_name = strdup(mon_name);
-       host->my_name = strdup(my_name);
+       host->mon_name = (const char *)strdup(mon_name);
+       host->my_name = (const char *)strdup(my_name);
+       host->notify_arg = strdup(opt_srcaddr != NULL ?
+                                       nsm_hostname : my_name);
        if (host->name == NULL ||
            host->mon_name == NULL ||
-           host->my_name == NULL) {
-               free(host->my_name);
-               free(host->mon_name);
+           host->my_name == NULL ||
+           host->notify_arg == NULL) {
+               free(host->notify_arg);
+               free((void *)host->my_name);
+               free((void *)host->mon_name);
                free(host->name);
                free(host);
                goto out_nomem;
@@ -135,8 +240,9 @@ static void smn_forget_host(struct nsm_host *host)
 
        nsm_delete_notified_host(host->name, host->mon_name, host->my_name);
 
-       free(host->my_name);
-       free(host->mon_name);
+       free(host->notify_arg);
+       free((void *)host->my_name);
+       free((void *)host->mon_name);
        free(host->name);
        if (host->ai)
                freeaddrinfo(host->ai);
@@ -157,7 +263,6 @@ smn_get_host(const char *hostname,
                return 0;
 
        insert_host(host);
-       xlog(D_GENERAL, "Added host %s to notify list", hostname);
        return 1;
 }
 
@@ -395,12 +500,14 @@ usage:            fprintf(stderr,
                exit(1);
        }
 
-       xlog_syslog(1);
        if (opt_debug) {
+               xlog_syslog(0);
                xlog_stderr(1);
                xlog_config(D_ALL, 1);
-       } else
+       } else {
+               xlog_syslog(1);
                xlog_stderr(0);
+       }
 
        xlog_open(progname);
        xlog(L_NOTICE, "Version " VERSION " starting");
@@ -414,32 +521,14 @@ usage:            fprintf(stderr,
        }
 
        if (opt_srcaddr != NULL) {
-               struct addrinfo *ai = NULL;
-               struct addrinfo hint = {
-                       .ai_family      = AF_UNSPEC,
-                       .ai_flags       = AI_NUMERICHOST,
-               };
-
-               if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
-                       /* not a presentation address - use it */
-                       strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
-               else {
-                       /* was a presentation address - look it up in
-                        * /etc/hosts, so it can be used for my_name */
-                       int error;
+               char *name;
 
-                       freeaddrinfo(ai);
-                       hint.ai_flags = AI_CANONNAME;
-                       error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
-                       if (error != 0) {
-                               xlog(L_ERROR, "Bind address %s is unusable: %s",
-                                               opt_srcaddr, gai_strerror(error));
-                               exit(1);
-                       }
-                       strncpy(nsm_hostname, ai->ai_canonname,
-                                                       sizeof(nsm_hostname));
-                       freeaddrinfo(ai);
-               }
+               name = smn_verify_my_name(opt_srcaddr);
+               if (name == NULL)
+                       exit(1);
+
+               strncpy(nsm_hostname, name, sizeof(nsm_hostname));
+               free(name);
        }
 
        (void)nsm_retire_monitored_hosts();
@@ -557,8 +646,6 @@ notify(const int sock)
 static int
 notify_host(int sock, struct nsm_host *host)
 {
-       const char *my_name = (opt_srcaddr != NULL ?
-                                       nsm_hostname : host->my_name);
        struct sockaddr *sap;
        socklen_t salen;
 
@@ -604,11 +691,30 @@ notify_host(int sock, struct nsm_host *host)
                host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
        else
                host->xid = nsm_xmit_notify(sock, sap, salen,
-                                       SM_PROG, my_name, nsm_state);
+                                       SM_PROG, host->notify_arg, nsm_state);
 
        return 0;
 }
 
+static void
+smn_defer(struct nsm_host *host)
+{
+       host->xid = 0;
+       host->send_next = time(NULL) + NSM_MAX_TIMEOUT;
+       host->timeout = NSM_MAX_TIMEOUT;
+       insert_host(host);
+}
+
+static void
+smn_schedule(struct nsm_host *host)
+{
+       host->retries = 0;
+       host->xid = 0;
+       host->send_next = time(NULL);
+       host->timeout = NSM_TIMEOUT;
+       insert_host(host);
+}
+
 /*
  * Extract the returned port number and set up the SM_NOTIFY call.
  */
@@ -617,21 +723,16 @@ recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
 {
        uint16_t port = nsm_recv_rpcbind(sap->sa_family, xdr);
 
-       host->send_next = time(NULL);
-       host->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;
+               smn_defer(host);
        } else {
+               xlog(D_GENERAL, "Processing rpcbind reply for %s (port %u)",
+                       host->name, port);
                nfs_set_port(sap, port);
-               if (host->timeout >= NSM_MAX_TIMEOUT / 4)
-                       host->timeout = NSM_MAX_TIMEOUT / 4;
+               smn_schedule(host);
        }
-
-       insert_host(host);
 }
 
 /*
@@ -644,15 +745,11 @@ recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
 static void
 recv_notify_reply(struct nsm_host *host)
 {
-       char *dot = strchr(host->my_name, '.');
+       char *dot = strchr(host->notify_arg, '.');
 
        if (dot != NULL) {
                *dot = '\0';
-               host->send_next = time(NULL);
-               host->xid = 0;
-               if (host->timeout >= NSM_MAX_TIMEOUT / 4)
-                       host->timeout = NSM_MAX_TIMEOUT / 4;
-               insert_host(host);
+               smn_schedule(host);
        } else {
                xlog(D_GENERAL, "Host %s notified successfully", host->name);
                smn_forget_host(host);
@@ -701,7 +798,7 @@ out:
 }
 
 /*
- * Insert host into sorted list
+ * Insert host into notification list, sorted by next send time
  */
 static void
 insert_host(struct nsm_host *host)
@@ -726,6 +823,7 @@ insert_host(struct nsm_host *host)
 
        host->next = *where;
        *where = host;
+       xlog(D_GENERAL, "Added host %s to notify list", host->name);
 }
 
 /*
index c7805eeaf8d3c185d8755b03b155d0404ac1551b..1b345a5479326986a96bac58860efccf0c9024d5 100644 (file)
@@ -1,8 +1,8 @@
-#!/bin/sh -p
+#!/bin/bash -p
 # nfsmount calls this script when mounting a filesystem with locking
 # enabled, but when statd does not seem to be running (based on
 # /var/run/rpc.statd.pid).
-# It should run run statd with whatever flags are apropriate for this
+# It should run statd with whatever flags are apropriate for this
 # site.
 PATH=/sbin:/usr/sbin
 exec rpc.statd --no-notify
index b72236c74b8a0573de88bd848e37003cbd0f3c49..c3c53548f35d387be245c18f5822aa1aa98cc976 100644 (file)
@@ -219,7 +219,10 @@ for details.
 Specifies the port number used for RPC listener sockets.
 If this option is not specified,
 .B rpc.statd
-chooses a random ephemeral port for each listener socket.
+will try to consult
+.IR /etc/services ,
+if gets port succeed, set the same port for all listener socket,
+otherwise 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.
@@ -347,8 +350,7 @@ of the requesting lock manager.
 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
+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