ecb0518
diff --git a/aclocal/kerberos5.m4 b/aclocal/kerberos5.m4
ecb0518
index 8a0f3e4..faa5804 100644
ecb0518
--- a/aclocal/kerberos5.m4
ecb0518
+++ b/aclocal/kerberos5.m4
ecb0518
@@ -38,9 +38,11 @@ AC_DEFUN([AC_KERBEROS_V5],[
ecb0518
       AC_DEFINE_UNQUOTED(KRB5_VERSION, $K5VERS, [Define this as the Kerberos version number])
ecb0518
       if test -f $dir/include/gssapi/gssapi_krb5.h -a \
ecb0518
                 \( -f $dir/lib/libgssapi_krb5.a -o \
ecb0518
+                   -f $dir/lib/libgssapi_krb5.so -o \
ecb0518
+                   -f $dir/lib32/libgssapi_krb5.a -o \
ecb0518
+                   -f $dir/lib32/libgssapi_krb5.so -o \
ecb0518
                    -f $dir/lib64/libgssapi_krb5.a -o \
ecb0518
-                   -f $dir/lib64/libgssapi_krb5.so -o \
ecb0518
-                   -f $dir/lib/libgssapi_krb5.so \) ; then
ecb0518
+                   -f $dir/lib64/libgssapi_krb5.so \) ; then
ecb0518
          AC_DEFINE(HAVE_KRB5, 1, [Define this if you have MIT Kerberos libraries])
ecb0518
          KRBDIR="$dir"
ecb0518
          gssapi_lib=gssapi_krb5
ecb0518
diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
ecb0518
index 84e4802..f078a66 100644
ecb0518
--- a/support/misc/nfsd_path.c
ecb0518
+++ b/support/misc/nfsd_path.c
ecb0518
@@ -1,3 +1,7 @@
ecb0518
+#ifdef HAVE_CONFIG_H
ecb0518
+#include <config.h>
ecb0518
+#endif
ecb0518
+
ecb0518
 #include <errno.h>
ecb0518
 #include <sys/types.h>
ecb0518
 #include <sys/stat.h>
ecb0518
@@ -5,7 +9,6 @@
ecb0518
 #include <stdlib.h>
ecb0518
 #include <unistd.h>
ecb0518
 
ecb0518
-#include "config.h"
ecb0518
 #include "conffile.h"
ecb0518
 #include "xmalloc.h"
ecb0518
 #include "xlog.h"
ecb0518
diff --git a/support/misc/xstat.c b/support/misc/xstat.c
ecb0518
index fa04788..4c997ee 100644
ecb0518
--- a/support/misc/xstat.c
ecb0518
+++ b/support/misc/xstat.c
ecb0518
@@ -1,3 +1,7 @@
ecb0518
+#ifdef HAVE_CONFIG_H
ecb0518
+#include <config.h>
ecb0518
+#endif
ecb0518
+
ecb0518
 #include <errno.h>
ecb0518
 #include <sys/types.h>
ecb0518
 #include <fcntl.h>
ecb0518
@@ -5,7 +9,6 @@
ecb0518
 #include <sys/sysmacros.h>
ecb0518
 #include <unistd.h>
ecb0518
 
ecb0518
-#include "config.h"
ecb0518
 #include "xstat.h"
ecb0518
 
ecb0518
 #ifdef HAVE_FSTATAT
ecb0518
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
ecb0518
index b6400be..6ba8a35 100644
ecb0518
--- a/support/nfs/conffile.c
ecb0518
+++ b/support/nfs/conffile.c
ecb0518
@@ -500,7 +500,7 @@ conf_readfile(const char *path)
ecb0518
 
ecb0518
 	if ((stat (path, &sb) == 0) || (errno != ENOENT)) {
ecb0518
 		char *new_conf_addr = NULL;
ecb0518
-		size_t sz = sb.st_size;
ecb0518
+		off_t sz;
ecb0518
 		int fd = open (path, O_RDONLY, 0);
ecb0518
 
ecb0518
 		if (fd == -1) {
ecb0518
@@ -517,6 +517,11 @@ conf_readfile(const char *path)
ecb0518
 
ecb0518
 		/* only after we have the lock, check the file size ready to read it */
ecb0518
 		sz = lseek(fd, 0, SEEK_END);
ecb0518
+		if (sz < 0) {
ecb0518
+			xlog_warn("conf_readfile: unable to determine file size: %s",
ecb0518
+				  strerror(errno));
ecb0518
+			goto fail;
ecb0518
+		}
ecb0518
 		lseek(fd, 0, SEEK_SET);
ecb0518
 
ecb0518
 		new_conf_addr = malloc(sz+1);
ecb0518
@@ -2162,6 +2167,7 @@ conf_write(const char *filename, const char *section, const char *arg,
ecb0518
 	ret = 0;
ecb0518
 
ecb0518
 cleanup:
ecb0518
+	flush_outqueue(&inqueue, NULL);
ecb0518
 	flush_outqueue(&outqueue, NULL);
ecb0518
 
ecb0518
 	if (buff)
ecb0518
diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c
ecb0518
index 7b8a871..9299e65 100644
ecb0518
--- a/support/nfsidmap/libnfsidmap.c
ecb0518
+++ b/support/nfsidmap/libnfsidmap.c
ecb0518
@@ -486,6 +486,9 @@ out:
ecb0518
 	if (gss_methods)
ecb0518
 		conf_free_list(gss_methods);
ecb0518
 
ecb0518
+	if (nfs4_methods)
ecb0518
+		conf_free_list(nfs4_methods);
ecb0518
+
ecb0518
 	return ret ? -ENOENT: 0;
ecb0518
 }
ecb0518
 
ecb0518
diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c
ecb0518
index 737f109..eec98fd 100644
ecb0518
--- a/systemd/nfs-server-generator.c
ecb0518
+++ b/systemd/nfs-server-generator.c
ecb0518
@@ -25,6 +25,7 @@
ecb0518
 #include <ctype.h>
ecb0518
 #include <stdio.h>
ecb0518
 #include <mntent.h>
ecb0518
+#include <alloca.h>
ecb0518
 
ecb0518
 #include "misc.h"
ecb0518
 #include "nfslib.h"
ecb0518
@@ -98,7 +99,7 @@ int main(int argc, char *argv[])
ecb0518
 		exit(1);
ecb0518
 	}
ecb0518
 
ecb0518
-	path = malloc(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase));
ecb0518
+	path = alloca(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase));
ecb0518
 	if (!path)
ecb0518
 		exit(2);
ecb0518
 	if (export_read(_PATH_EXPORTS, 1) +
ecb0518
diff --git a/tests/statdb_dump.c b/tests/statdb_dump.c
ecb0518
index 92d63f2..3ac12bf 100644
ecb0518
--- a/tests/statdb_dump.c
ecb0518
+++ b/tests/statdb_dump.c
ecb0518
@@ -23,6 +23,7 @@
ecb0518
 #include "config.h"
ecb0518
 #endif
ecb0518
 
ecb0518
+#include <string.h>
ecb0518
 #include <stdio.h>
ecb0518
 #include <errno.h>
ecb0518
 #include <arpa/inet.h>
ecb0518
diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py
ecb0518
index 2f525f4..6ac83cc 100755
ecb0518
--- a/tools/mountstats/mountstats.py
ecb0518
+++ b/tools/mountstats/mountstats.py
ecb0518
@@ -308,6 +308,8 @@ class DeviceData:
ecb0518
             op = words[0][:-1]
ecb0518
             self.__rpc_data['ops'] += [op]
ecb0518
             self.__rpc_data[op] = [int(word) for word in words[1:]]
ecb0518
+            if len(self.__rpc_data[op]) < 9:
ecb0518
+                self.__rpc_data[op] += [0]
ecb0518
 
ecb0518
     def parse_stats(self, lines):
ecb0518
         """Turn a list of lines from a mount stat file into a 
ecb0518
@@ -582,7 +584,7 @@ class DeviceData:
ecb0518
             self.__nfs_data['fstype'] = 'nfs4'
ecb0518
         self.__rpc_data['ops'] = ops
ecb0518
         for op in ops:
ecb0518
-            self.__rpc_data[op] = [0 for i in range(8)]
ecb0518
+            self.__rpc_data[op] = [0 for i in range(9)]
ecb0518
 
ecb0518
     def accumulate_iostats(self, new_stats):
ecb0518
         """Accumulate counters from all RPC op buckets in new_stats.  This is
ecb0518
@@ -607,6 +609,8 @@ class DeviceData:
ecb0518
         queued_for = float(rpc_stats[5])
ecb0518
         rtt = float(rpc_stats[6])
ecb0518
         exe = float(rpc_stats[7])
ecb0518
+        if len(rpc_stats) >= 9:
ecb0518
+            errs = int(rpc_stats[8])
ecb0518
 
ecb0518
         # prevent floating point exceptions
ecb0518
         if ops != 0:
ecb0518
@@ -615,12 +619,15 @@ class DeviceData:
ecb0518
             rtt_per_op = rtt / ops
ecb0518
             exe_per_op = exe / ops
ecb0518
             queued_for_per_op = queued_for / ops
ecb0518
+            if len(rpc_stats) >= 9:
ecb0518
+                errs_percent = (errs * 100) / ops
ecb0518
         else:
ecb0518
             kb_per_op = 0.0
ecb0518
             retrans_percent = 0.0
ecb0518
             rtt_per_op = 0.0
ecb0518
             exe_per_op = 0.0
ecb0518
             queued_for_per_op = 0.0
ecb0518
+            errs_percent = 0.0
ecb0518
 
ecb0518
         op += ':'
ecb0518
         print(format(op.lower(), '<16s'), end='')
ecb0518
@@ -630,7 +637,10 @@ class DeviceData:
ecb0518
         print(format('retrans', '>16s'), end='')
ecb0518
         print(format('avg RTT (ms)', '>16s'), end='')
ecb0518
         print(format('avg exe (ms)', '>16s'), end='')
ecb0518
-        print(format('avg queue (ms)', '>16s'))
ecb0518
+        print(format('avg queue (ms)', '>16s'), end='')
ecb0518
+        if len(rpc_stats) >= 9:
ecb0518
+            print(format('errors', '>16s'), end='')
ecb0518
+        print()
ecb0518
 
ecb0518
         print(format((ops / sample_time), '>24.3f'), end='')
ecb0518
         print(format((kilobytes / sample_time), '>16.3f'), end='')
ecb0518
@@ -639,7 +649,11 @@ class DeviceData:
ecb0518
         print(format(retransmits, '>16'), end='')
ecb0518
         print(format(rtt_per_op, '>16.3f'), end='')
ecb0518
         print(format(exe_per_op, '>16.3f'), end='')
ecb0518
-        print(format(queued_for_per_op, '>16.3f'))
ecb0518
+        print(format(queued_for_per_op, '>16.3f'), end='')
ecb0518
+        if len(rpc_stats) >= 9:
ecb0518
+            errors = '{0:>10.0f} ({1:>3.1f}%)'.format(errs, errs_percent).strip()
ecb0518
+            print(format(errors, '>16'), end='')
ecb0518
+        print()
ecb0518
 
ecb0518
     def display_iostats(self, sample_time):
ecb0518
         """Display NFS and RPC stats in an iostat-like way
ecb0518
diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
ecb0518
old mode 100644
ecb0518
new mode 100755
ecb0518
index dec0e86..b7e98a2
ecb0518
--- a/tools/nfs-iostat/nfs-iostat.py
ecb0518
+++ b/tools/nfs-iostat/nfs-iostat.py
ecb0518
@@ -329,6 +329,8 @@ class DeviceData:
ecb0518
         queued_for = float(rpc_stats[5])
ecb0518
         rtt = float(rpc_stats[6])
ecb0518
         exe = float(rpc_stats[7])
ecb0518
+        if len(rpc_stats) >= 9:
ecb0518
+            errs = float(rpc_stats[8])
ecb0518
 
ecb0518
         # prevent floating point exceptions
ecb0518
         if ops != 0:
ecb0518
@@ -337,12 +339,16 @@ class DeviceData:
ecb0518
             rtt_per_op = rtt / ops
ecb0518
             exe_per_op = exe / ops
ecb0518
             queued_for_per_op = queued_for / ops
ecb0518
+            if len(rpc_stats) >= 9:
ecb0518
+                errs_percent = (errs * 100) / ops
ecb0518
         else:
ecb0518
             kb_per_op = 0.0
ecb0518
             retrans_percent = 0.0
ecb0518
             rtt_per_op = 0.0
ecb0518
             exe_per_op = 0.0
ecb0518
             queued_for_per_op = 0.0
ecb0518
+            if len(rpc_stats) >= 9:
ecb0518
+                errs_percent = 0.0
ecb0518
 
ecb0518
         op += ':'
ecb0518
         print(format(op.lower(), '<16s'), end='')
ecb0518
@@ -352,7 +358,10 @@ class DeviceData:
ecb0518
         print(format('retrans', '>16s'), end='')
ecb0518
         print(format('avg RTT (ms)', '>16s'), end='')
ecb0518
         print(format('avg exe (ms)', '>16s'), end='')
ecb0518
-        print(format('avg queue (ms)', '>16s'))
ecb0518
+        print(format('avg queue (ms)', '>16s'), end='')
ecb0518
+        if len(rpc_stats) >= 9:
ecb0518
+            print(format('errors', '>16s'), end='')
ecb0518
+        print()
ecb0518
 
ecb0518
         print(format((ops / sample_time), '>24.3f'), end='')
ecb0518
         print(format((kilobytes / sample_time), '>16.3f'), end='')
ecb0518
@@ -361,7 +370,11 @@ class DeviceData:
ecb0518
         print(format(retransmits, '>16'), end='')
ecb0518
         print(format(rtt_per_op, '>16.3f'), end='')
ecb0518
         print(format(exe_per_op, '>16.3f'), end='')
ecb0518
-        print(format(queued_for_per_op, '>16.3f'))
ecb0518
+        print(format(queued_for_per_op, '>16.3f'), end='')
ecb0518
+        if len(rpc_stats) >= 9:
ecb0518
+            errors = '{0:>10.0f} ({1:>3.1f}%)'.format(errs, errs_percent).strip()
ecb0518
+            print(format(errors, '>16'), end='')
ecb0518
+        print()
ecb0518
 
ecb0518
     def ops(self, sample_time):
ecb0518
         sends = float(self.__rpc_data['rpcsends'])
ecb0518
diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man
ecb0518
index 9ae94c5..940c043 100644
ecb0518
--- a/tools/nfs-iostat/nfsiostat.man
ecb0518
+++ b/tools/nfs-iostat/nfsiostat.man
ecb0518
@@ -97,6 +97,14 @@ This is the duration from the time the NFS client created the RPC request task t
ecb0518
 .RE
ecb0518
 .RE
ecb0518
 .RE
ecb0518
+.RS 8
ecb0518
+- \fBerrors\fR
ecb0518
+.RS
ecb0518
+This is the number of operations that completed with an error status (status < 0).  This count is only available on kernels with RPC iostats version 1.1 or above.
ecb0518
+.RS
ecb0518
+.RE
ecb0518
+.RE
ecb0518
+.RE
ecb0518
 .TP
ecb0518
 Note that if an interval is used as argument to \fBnfsiostat\fR, then the diffrence from previous interval will be displayed, otherwise the results will be from the time that the share was mounted.
ecb0518
 
ecb0518
diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c
ecb0518
index e811703..f5f9b10 100644
ecb0518
--- a/utils/blkmapd/device-discovery.c
ecb0518
+++ b/utils/blkmapd/device-discovery.c
ecb0518
@@ -26,6 +26,10 @@
ecb0518
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ecb0518
  */
ecb0518
 
ecb0518
+#ifdef HAVE_CONFIG_H
ecb0518
+#include "config.h"
ecb0518
+#endif /* HAVE_CONFIG_H */
ecb0518
+
ecb0518
 #include <sys/sysmacros.h>
ecb0518
 #include <sys/types.h>
ecb0518
 #include <sys/stat.h>
ecb0518
@@ -51,10 +55,6 @@
ecb0518
 #include <errno.h>
ecb0518
 #include <libdevmapper.h>
ecb0518
 
ecb0518
-#ifdef HAVE_CONFIG_H
ecb0518
-#include "config.h"
ecb0518
-#endif /* HAVE_CONFIG_H */
ecb0518
-
ecb0518
 #include "device-discovery.h"
ecb0518
 #include "xcommon.h"
ecb0518
 #include "nfslib.h"
ecb0518
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
ecb0518
index e620f0d..cc3a210 100644
ecb0518
--- a/utils/gssd/gssd.man
ecb0518
+++ b/utils/gssd/gssd.man
ecb0518
@@ -305,6 +305,14 @@ section of the
ecb0518
 .I /etc/nfs.conf
ecb0518
 configuration file.  Values recognized include:
ecb0518
 .TP
ecb0518
+.B verbosity
ecb0518
+Value which is equivalent to the number of
ecb0518
+.BR -v .
ecb0518
+.TP
ecb0518
+.B rpc-verbosity
ecb0518
+Value which is equivalent to the number of
ecb0518
+.BR -r .
ecb0518
+.TP
ecb0518
 .B use-memcache
ecb0518
 A Boolean flag equivalent to
ecb0518
 .BR -M .
ecb0518
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
ecb0518
index 454a6eb..0474783 100644
ecb0518
--- a/utils/gssd/krb5_util.c
ecb0518
+++ b/utils/gssd/krb5_util.c
ecb0518
@@ -912,6 +912,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt,
ecb0518
 				k5err = gssd_k5_err_msg(context, code);
ecb0518
 				printerr(3, "%s while getting keytab entry for '%s'\n",
ecb0518
 					 k5err, spn);
ecb0518
+				free(k5err);
ecb0518
+				k5err = NULL;
ecb0518
 				/*
ecb0518
 				 * We tried the active directory machine account
ecb0518
 				 * with the hostname part as-is and failed...
ecb0518
@@ -1014,6 +1016,8 @@ query_krb5_ccache(const char* cred_cache, char **ret_princname,
ecb0518
 	char *str = NULL;
ecb0518
 	char *princstring;
ecb0518
 
ecb0518
+	*ret_princname = *ret_realm = NULL;
ecb0518
+
ecb0518
 	ret = krb5_init_context(&context);
ecb0518
 	if (ret) 
ecb0518
 		return 0;
ecb0518
@@ -1048,7 +1052,7 @@ err_princ:
ecb0518
 	krb5_cc_close(context, ccache);
ecb0518
 err_cache:
ecb0518
 	krb5_free_context(context);
ecb0518
-	return found;
ecb0518
+	return (*ret_princname && *ret_realm);
ecb0518
 }
ecb0518
 
ecb0518
 /*==========================*/
ecb0518
@@ -1231,6 +1235,8 @@ gssd_destroy_krb5_machine_creds(void)
ecb0518
 			k5err = gssd_k5_err_msg(context, code);
ecb0518
 			printerr(0, "WARNING: %s while destroying credential "
ecb0518
 				    "cache '%s'\n", k5err, ple->ccname);
ecb0518
+			free(k5err);
ecb0518
+			k5err = NULL;
ecb0518
 		}
ecb0518
 	}
ecb0518
 	krb5_free_context(context);
ecb0518
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
ecb0518
index 62e37b8..c187e7d 100644
ecb0518
--- a/utils/idmapd/idmapd.c
ecb0518
+++ b/utils/idmapd/idmapd.c
ecb0518
@@ -34,6 +34,10 @@
ecb0518
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ecb0518
  */
ecb0518
 
ecb0518
+#ifdef HAVE_CONFIG_H
ecb0518
+#include "config.h"
ecb0518
+#endif /* HAVE_CONFIG_H */
ecb0518
+
ecb0518
 #include <sys/types.h>
ecb0518
 #include <sys/time.h>
ecb0518
 #include <sys/inotify.h>
ecb0518
@@ -62,10 +66,6 @@
ecb0518
 #include <libgen.h>
ecb0518
 #include <nfsidmap.h>
ecb0518
 
ecb0518
-#ifdef HAVE_CONFIG_H
ecb0518
-#include "config.h"
ecb0518
-#endif /* HAVE_CONFIG_H */
ecb0518
-
ecb0518
 #include "xlog.h"
ecb0518
 #include "conffile.h"
ecb0518
 #include "queue.h"
ecb0518
@@ -520,14 +520,16 @@ static void
ecb0518
 clntscancb(int UNUSED(fd), short UNUSED(which), void *data)
ecb0518
 {
ecb0518
 	struct idmap_clientq *icq = data;
ecb0518
-	struct idmap_client *ic;
ecb0518
+	struct idmap_client *ic, *ic_next;
ecb0518
 
ecb0518
-	TAILQ_FOREACH(ic, icq, ic_next)
ecb0518
+	for (ic = TAILQ_FIRST(icq); ic != NULL; ic = ic_next) { 
ecb0518
+		ic_next = TAILQ_NEXT(ic, ic_next);
ecb0518
 		if (ic->ic_fd == -1 && nfsopen(ic) == -1) {
ecb0518
 			close(ic->ic_dirfd);
ecb0518
 			TAILQ_REMOVE(icq, ic, ic_next);
ecb0518
 			free(ic);
ecb0518
 		}
ecb0518
+	}
ecb0518
 }
ecb0518
 
ecb0518
 static void
ecb0518
diff --git a/utils/mount/network.c b/utils/mount/network.c
ecb0518
index e166a82..6ac913d 100644
ecb0518
--- a/utils/mount/network.c
ecb0518
+++ b/utils/mount/network.c
ecb0518
@@ -39,7 +39,7 @@
ecb0518
 #include <sys/socket.h>
ecb0518
 #include <sys/wait.h>
ecb0518
 #include <sys/stat.h>
ecb0518
-#if defined(__GLIBC__) && (__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)
ecb0518
+#if defined(__GLIBC__) && ((__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24))
ecb0518
 /* Cannot safely include linux/in6.h in old glibc, so hardcode the needed values */
ecb0518
 # define IPV6_PREFER_SRC_PUBLIC 2
ecb0518
 # define IPV6_ADDR_PREFERENCES 72
ecb0518
diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
ecb0518
index 9ee9bd9..6ba9cef 100644
ecb0518
--- a/utils/mount/nfs.man
ecb0518
+++ b/utils/mount/nfs.man
ecb0518
@@ -1252,7 +1252,7 @@ If absolute cache coherence among clients is required,
ecb0518
 applications should use file locking. Alternatively, applications
ecb0518
 can also open their files with the O_DIRECT flag
ecb0518
 to disable data caching entirely.
ecb0518
-.SS "File timestamp maintainence"
ecb0518
+.SS "File timestamp maintenance"
ecb0518
 NFS servers are responsible for managing file and directory timestamps
ecb0518
 .RB ( atime ,
ecb0518
 .BR ctime ", and"
ecb0518
diff --git a/utils/nfsdcld/legacy.c b/utils/nfsdcld/legacy.c
ecb0518
index f0ca316..07f477a 100644
ecb0518
--- a/utils/nfsdcld/legacy.c
ecb0518
+++ b/utils/nfsdcld/legacy.c
ecb0518
@@ -24,6 +24,7 @@
ecb0518
 #include <errno.h>
ecb0518
 #include <sys/types.h>
ecb0518
 #include <sys/stat.h>
ecb0518
+#include <limits.h>
ecb0518
 #include "cld.h"
ecb0518
 #include "sqlite.h"
ecb0518
 #include "xlog.h"
ecb0518
diff --git a/utils/nfsdcld/sqlite.c b/utils/nfsdcld/sqlite.c
ecb0518
index cd658ef..fa81df8 100644
ecb0518
--- a/utils/nfsdcld/sqlite.c
ecb0518
+++ b/utils/nfsdcld/sqlite.c
ecb0518
@@ -67,6 +67,7 @@
ecb0518
 #include "cld-internal.h"
ecb0518
 #include "conffile.h"
ecb0518
 #include "legacy.h"
ecb0518
+#include "nfslib.h"
ecb0518
 
ecb0518
 #define CLD_SQLITE_LATEST_SCHEMA_VERSION 3
ecb0518
 #define CLTRACK_DEFAULT_STORAGEDIR NFS_STATEDIR "/nfsdcltrack"
ecb0518
@@ -448,6 +449,129 @@ out:
ecb0518
 	return ret;
ecb0518
 }
ecb0518
 
ecb0518
+/*
ecb0518
+ * Helper for renaming a recovery table to fix the padding.
ecb0518
+ */
ecb0518
+static int
ecb0518
+sqlite_fix_table_name(const char *name)
ecb0518
+{
ecb0518
+	int ret;
ecb0518
+	uint64_t val;
ecb0518
+	char *err;
ecb0518
+
ecb0518
+	if (sscanf(name, "rec-%" PRIx64, &val) != 1)
ecb0518
+		return -EINVAL;
ecb0518
+	ret = snprintf(buf, sizeof(buf), "ALTER TABLE \"%s\" "
ecb0518
+			"RENAME TO \"rec-%016" PRIx64 "\";",
ecb0518
+			name, val);
ecb0518
+	if (ret < 0) {
ecb0518
+		xlog(L_ERROR, "sprintf failed!");
ecb0518
+		return -EINVAL;
ecb0518
+	} else if ((size_t)ret >= sizeof(buf)) {
ecb0518
+		xlog(L_ERROR, "sprintf output too long! (%d chars)", ret);
ecb0518
+		return -EINVAL;
ecb0518
+	}
ecb0518
+	ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err;;
ecb0518
+	if (ret != SQLITE_OK) {
ecb0518
+		xlog(L_ERROR, "Unable to fix table for epoch %d: %s",
ecb0518
+		     val, err);
ecb0518
+		goto out;
ecb0518
+	}
ecb0518
+	xlog(D_GENERAL, "Renamed table %s to rec-%016" PRIx64, name, val);
ecb0518
+out:
ecb0518
+	sqlite3_free(err);
ecb0518
+	return ret;
ecb0518
+}
ecb0518
+
ecb0518
+/*
ecb0518
+ * Callback for the sqlite_exec statement in sqlite_check_table_names.
ecb0518
+ * If the epoch encoded in the table name matches either the current
ecb0518
+ * epoch or the recovery epoch, then try to fix the padding.  Otherwise,
ecb0518
+ * we bail.
ecb0518
+ */
ecb0518
+static int
ecb0518
+sqlite_check_table_names_cb(void *UNUSED(arg), int ncols, char **cols,
ecb0518
+			    char **UNUSED(colnames))
ecb0518
+{
ecb0518
+	int ret = SQLITE_OK;
ecb0518
+	uint64_t val;
ecb0518
+
ecb0518
+	if (ncols > 1)
ecb0518
+		return -EINVAL;
ecb0518
+	if (sscanf(cols[0], "rec-%" PRIx64, &val) != 1)
ecb0518
+		return -EINVAL;
ecb0518
+	if (val == current_epoch || val == recovery_epoch) {
ecb0518
+		xlog(D_GENERAL, "found invalid table name %s for %s epoch",
ecb0518
+		     cols[0], val == current_epoch ? "current" : "recovery");
ecb0518
+		ret = sqlite_fix_table_name(cols[0]);
ecb0518
+	} else {
ecb0518
+		xlog(L_ERROR, "found invalid table name %s for unknown epoch %"
ecb0518
+		     PRId64, cols[0], val);
ecb0518
+		return -EINVAL;
ecb0518
+	}
ecb0518
+	return ret;
ecb0518
+}
ecb0518
+
ecb0518
+/*
ecb0518
+ * Look for recovery table names where the epoch isn't zero-padded
ecb0518
+ */
ecb0518
+static int
ecb0518
+sqlite_check_table_names(void)
ecb0518
+{
ecb0518
+	int ret;
ecb0518
+	char *err;
ecb0518
+
ecb0518
+	ret = sqlite3_exec(dbh, "SELECT name FROM sqlite_master "
ecb0518
+			   "WHERE type=\"table\" AND name LIKE \"%rec-%\" "
ecb0518
+			   "AND length(name) < 20;",
ecb0518
+			   sqlite_check_table_names_cb, NULL, &err;;
ecb0518
+	if (ret != SQLITE_OK) {
ecb0518
+		xlog(L_ERROR, "Table names check failed: %s", err);
ecb0518
+	}
ecb0518
+	sqlite3_free(err);
ecb0518
+	return ret;
ecb0518
+}
ecb0518
+
ecb0518
+/*
ecb0518
+ * Simple db health check.  For now we're just making sure that the recovery
ecb0518
+ * table names are of the format "rec-CCCCCCCCCCCCCCCC" (where C is the hex
ecb0518
+ * representation of the epoch value) and that epoch value matches either
ecb0518
+ * the current epoch or the recovery epoch.
ecb0518
+ */
ecb0518
+static int
ecb0518
+sqlite_check_db_health(void)
ecb0518
+{
ecb0518
+	int ret, ret2;
ecb0518
+	char *err;
ecb0518
+
ecb0518
+	ret = sqlite3_exec(dbh, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL,
ecb0518
+				&err;;
ecb0518
+	if (ret != SQLITE_OK) {
ecb0518
+		xlog(L_ERROR, "Unable to begin transaction: %s", err);
ecb0518
+		goto rollback;
ecb0518
+	}
ecb0518
+
ecb0518
+	ret = sqlite_check_table_names();
ecb0518
+	if (ret != SQLITE_OK)
ecb0518
+		goto rollback;
ecb0518
+
ecb0518
+	ret = sqlite3_exec(dbh, "COMMIT TRANSACTION;", NULL, NULL, &err;;
ecb0518
+	if (ret != SQLITE_OK) {
ecb0518
+		xlog(L_ERROR, "Unable to commit transaction: %s", err);
ecb0518
+		goto rollback;
ecb0518
+	}
ecb0518
+
ecb0518
+cleanup:
ecb0518
+	sqlite3_free(err);
ecb0518
+	xlog(D_GENERAL, "%s: returning %d", __func__, ret);
ecb0518
+	return ret;
ecb0518
+rollback:
ecb0518
+	ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err;;
ecb0518
+	if (ret2 != SQLITE_OK)
ecb0518
+		xlog(L_ERROR, "Unable to rollback transaction: %s", err);
ecb0518
+	goto cleanup;
ecb0518
+}
ecb0518
+
ecb0518
 static int
ecb0518
 sqlite_attach_db(const char *path)
ecb0518
 {
ecb0518
@@ -536,7 +660,7 @@ sqlite_copy_cltrack_records(int *num_rec)
ecb0518
 		xlog(L_ERROR, "Unable to begin transaction: %s", err);
ecb0518
 		goto rollback;
ecb0518
 	}
ecb0518
-	ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%" PRIx64 "\";",
ecb0518
+	ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%016" PRIx64 "\";",
ecb0518
 			current_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
 		xlog(L_ERROR, "sprintf failed!");
ecb0518
@@ -551,7 +675,7 @@ sqlite_copy_cltrack_records(int *num_rec)
ecb0518
 		xlog(L_ERROR, "Unable to clear records from current epoch: %s", err);
ecb0518
 		goto rollback;
ecb0518
 	}
ecb0518
-	ret = snprintf(buf, sizeof(buf), "INSERT INTO \"rec-%" PRIx64 "\" "
ecb0518
+	ret = snprintf(buf, sizeof(buf), "INSERT INTO \"rec-%016" PRIx64 "\" "
ecb0518
 				"SELECT id FROM attached.clients;",
ecb0518
 				current_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
@@ -673,6 +797,13 @@ sqlite_prepare_dbh(const char *topdir)
ecb0518
 	if (ret)
ecb0518
 		goto out_close;
ecb0518
 
ecb0518
+	ret = sqlite_check_db_health();
ecb0518
+	if (ret) {
ecb0518
+		xlog(L_ERROR, "Database health check failed! "
ecb0518
+			"Database must be fixed manually.");
ecb0518
+		goto out_close;
ecb0518
+	}
ecb0518
+
ecb0518
 	/* one-time "upgrade" from older client tracking methods */
ecb0518
 	if (first_time) {
ecb0518
 		sqlite_copy_cltrack_records(&num_cltrack_records);
ecb0518
@@ -704,7 +835,7 @@ sqlite_insert_client(const unsigned char *clname, const size_t namelen)
ecb0518
 	int ret;
ecb0518
 	sqlite3_stmt *stmt = NULL;
ecb0518
 
ecb0518
-	ret = snprintf(buf, sizeof(buf), "INSERT OR REPLACE INTO \"rec-%" PRIx64 "\" "
ecb0518
+	ret = snprintf(buf, sizeof(buf), "INSERT OR REPLACE INTO \"rec-%016" PRIx64 "\" "
ecb0518
 				"VALUES (?);", current_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
 		xlog(L_ERROR, "sprintf failed!");
ecb0518
@@ -749,7 +880,7 @@ sqlite_remove_client(const unsigned char *clname, const size_t namelen)
ecb0518
 	int ret;
ecb0518
 	sqlite3_stmt *stmt = NULL;
ecb0518
 
ecb0518
-	ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%" PRIx64 "\" "
ecb0518
+	ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%016" PRIx64 "\" "
ecb0518
 				"WHERE id==?;", current_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
 		xlog(L_ERROR, "sprintf failed!");
ecb0518
@@ -799,7 +930,7 @@ sqlite_check_client(const unsigned char *clname, const size_t namelen)
ecb0518
 	int ret;
ecb0518
 	sqlite3_stmt *stmt = NULL;
ecb0518
 
ecb0518
-	ret = snprintf(buf, sizeof(buf), "SELECT count(*) FROM  \"rec-%" PRIx64 "\" "
ecb0518
+	ret = snprintf(buf, sizeof(buf), "SELECT count(*) FROM  \"rec-%016" PRIx64 "\" "
ecb0518
 				"WHERE id==?;", recovery_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
 		xlog(L_ERROR, "sprintf failed!");
ecb0518
@@ -892,7 +1023,7 @@ sqlite_grace_start(void)
ecb0518
 			goto rollback;
ecb0518
 		}
ecb0518
 
ecb0518
-		ret = snprintf(buf, sizeof(buf), "CREATE TABLE \"rec-%" PRIx64 "\" "
ecb0518
+		ret = snprintf(buf, sizeof(buf), "CREATE TABLE \"rec-%016" PRIx64 "\" "
ecb0518
 				"(id BLOB PRIMARY KEY);",
ecb0518
 				tcur);
ecb0518
 		if (ret < 0) {
ecb0518
@@ -916,7 +1047,7 @@ sqlite_grace_start(void)
ecb0518
 		 * values in the grace table, just clear out the records for
ecb0518
 		 * the current reboot epoch.
ecb0518
 		 */
ecb0518
-		ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%" PRIx64 "\";",
ecb0518
+		ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%016" PRIx64 "\";",
ecb0518
 				tcur);
ecb0518
 		if (ret < 0) {
ecb0518
 			xlog(L_ERROR, "sprintf failed!");
ecb0518
@@ -977,7 +1108,7 @@ sqlite_grace_done(void)
ecb0518
 		goto rollback;
ecb0518
 	}
ecb0518
 
ecb0518
-	ret = snprintf(buf, sizeof(buf), "DROP TABLE \"rec-%" PRIx64 "\";",
ecb0518
+	ret = snprintf(buf, sizeof(buf), "DROP TABLE \"rec-%016" PRIx64 "\";",
ecb0518
 		recovery_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
 		xlog(L_ERROR, "sprintf failed!");
ecb0518
@@ -1028,7 +1159,7 @@ sqlite_iterate_recovery(int (*cb)(struct cld_client *clnt), struct cld_client *c
ecb0518
 		return -EINVAL;
ecb0518
 	}
ecb0518
 
ecb0518
-	ret = snprintf(buf, sizeof(buf), "SELECT * FROM \"rec-%" PRIx64 "\";",
ecb0518
+	ret = snprintf(buf, sizeof(buf), "SELECT * FROM \"rec-%016" PRIx64 "\";",
ecb0518
 		recovery_epoch);
ecb0518
 	if (ret < 0) {
ecb0518
 		xlog(L_ERROR, "sprintf failed!");
ecb0518
diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c
ecb0518
index 9400048..20c8ebd 100644
ecb0518
--- a/utils/statd/monitor.c
ecb0518
+++ b/utils/statd/monitor.c
ecb0518
@@ -66,7 +66,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
ecb0518
 			*my_name  = argp->mon_id.my_id.my_name;
ecb0518
 	struct my_id	*id = &argp->mon_id.my_id;
ecb0518
 	char		*cp;
ecb0518
-	notify_list	*clnt;
ecb0518
+	notify_list	*clnt = NULL;
ecb0518
 	struct sockaddr_in my_addr = {
ecb0518
 		.sin_family		= AF_INET,
ecb0518
 		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
ecb0518
@@ -177,6 +177,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
ecb0518
 	 * We're committed...ignoring errors.  Let's hope that a malloc()
ecb0518
 	 * doesn't fail.  (I should probably fix this assumption.)
ecb0518
 	 */
ecb0518
+	clnt = NULL;
ecb0518
 	if (!existing && !(clnt = nlist_new(my_name, mon_name, 0))) {
ecb0518
 		free(dnsname);
ecb0518
 		xlog_warn("out of memory");
ecb0518
@@ -223,6 +224,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
ecb0518
 
ecb0518
 failure:
ecb0518
 	xlog_warn("STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
ecb0518
+	free(clnt);
ecb0518
 	return (&result);
ecb0518
 }
ecb0518
 
ecb0518
@@ -242,6 +244,7 @@ load_one_host(const char *hostname,
ecb0518
 	clnt->dns_name = strdup(hostname);
ecb0518
 	if (clnt->dns_name == NULL) {
ecb0518
 		nlist_free(NULL, clnt);
ecb0518
+		free(clnt);
ecb0518
 		return 0;
ecb0518
 	}
ecb0518
 
ecb0518
diff --git a/utils/statd/notlist.c b/utils/statd/notlist.c
ecb0518
index 0341c15..45879a4 100644
ecb0518
--- a/utils/statd/notlist.c
ecb0518
+++ b/utils/statd/notlist.c
ecb0518
@@ -210,7 +210,6 @@ nlist_free(notify_list **head, notify_list *entry)
ecb0518
 	if (NL_MON_NAME(entry))
ecb0518
 		free(NL_MON_NAME(entry));
ecb0518
 	free(entry->dns_name);
ecb0518
-	free(entry);
ecb0518
 }
ecb0518
 
ecb0518
 /* 
ecb0518
@@ -219,8 +218,14 @@ nlist_free(notify_list **head, notify_list *entry)
ecb0518
 void 
ecb0518
 nlist_kill(notify_list **head)
ecb0518
 {
ecb0518
-	while (*head)
ecb0518
+	notify_list *next;
ecb0518
+
ecb0518
+	while (*head) {
ecb0518
+		next = (*head)->next;
ecb0518
 		nlist_free(head, *head);
ecb0518
+		free(*head);
ecb0518
+		*head = next;
ecb0518
+	}
ecb0518
 }
ecb0518
 
ecb0518
 /*