walters / rpms / nfs-utils

Forked from rpms/nfs-utils 6 years ago
Clone
0b26fc7
diff --git a/.gitignore b/.gitignore
0b26fc7
index 126d12c..941aca0 100644
0b26fc7
--- a/.gitignore
0b26fc7
+++ b/.gitignore
0b26fc7
@@ -70,6 +70,7 @@ tests/nsm_client/nlm_sm_inter_svc.c
0b26fc7
 tests/nsm_client/nlm_sm_inter_xdr.c
0b26fc7
 utils/nfsidmap/nfsidmap
0b26fc7
 systemd/nfs-server-generator
0b26fc7
+systemd/rpc-pipefs-generator
0b26fc7
 systemd/nfs-config.service
0b26fc7
 systemd/rpc-gssd.service
0b26fc7
 # cscope database files
0b26fc7
diff --git a/nfs.conf b/nfs.conf
0b26fc7
index 81ece06..0d0ec9b 100644
0b26fc7
--- a/nfs.conf
0b26fc7
+++ b/nfs.conf
0b26fc7
@@ -1,7 +1,10 @@
0b26fc7
 #
0b26fc7
-# This is a general conifguration for the 
0b26fc7
+# This is a general configuration for the
0b26fc7
 # NFS daemons and tools
0b26fc7
 #
0b26fc7
+#[general]
0b26fc7
+# pipefs-directory=/var/lib/nfs/rpc_pipefs
0b26fc7
+#
0b26fc7
 #[exportfs]
0b26fc7
 # debug=0
0b26fc7
 #
0b26fc7
@@ -12,7 +15,6 @@
0b26fc7
 # limit-to-legacy-enctypes=0
0b26fc7
 # context-timeout=0
0b26fc7
 # rpc-timeout=5
0b26fc7
-# pipefs-directory=/var/lib/nfs/rpc_pipefs
0b26fc7
 # keytab-file=/etc/krb5.keytab
0b26fc7
 # cred-cache-directory=
0b26fc7
 # preferred-realm=
0b26fc7
@@ -42,7 +44,7 @@
0b26fc7
 # port=0
0b26fc7
 # grace-time=90
0b26fc7
 # lease-time=90
0b26fc7
-# udp=y
0b26fc7
+# udp=n
0b26fc7
 # tcp=y
0b26fc7
 # vers2=n
0b26fc7
 # vers3=y
0b26fc7
@@ -65,6 +67,7 @@
0b26fc7
 # retry-time=900
0b26fc7
 # outgoing-port=
0b26fc7
 # outgoing-addr=
0b26fc7
+# lift-grace=y
0b26fc7
 #
0b26fc7
 #[svcgssd]
0b26fc7
 # principal=
0b26fc7
diff --git a/support/export/xtab.c b/support/export/xtab.c
0b26fc7
index 22cf539..d42eeef 100644
0b26fc7
--- a/support/export/xtab.c
0b26fc7
+++ b/support/export/xtab.c
0b26fc7
@@ -14,12 +14,20 @@
0b26fc7
 #include <unistd.h>
0b26fc7
 #include <stdlib.h>
0b26fc7
 #include <string.h>
0b26fc7
+#include <sys/types.h>
0b26fc7
+#include <sys/stat.h>
0b26fc7
+#include <errno.h>
0b26fc7
+#include <libgen.h>
0b26fc7
 
0b26fc7
 #include "nfslib.h"
0b26fc7
 #include "exportfs.h"
0b26fc7
 #include "xio.h"
0b26fc7
 #include "xlog.h"
0b26fc7
 #include "v4root.h"
0b26fc7
+#include "misc.h"
0b26fc7
+
0b26fc7
+static char state_base_dirname[PATH_MAX] = NFS_STATEDIR;
0b26fc7
+extern struct state_paths etab;
0b26fc7
 
0b26fc7
 int v4root_needed;
0b26fc7
 static void cond_rename(char *newfile, char *oldfile);
0b26fc7
@@ -65,7 +73,7 @@ xtab_read(char *xtab, char *lockfn, int is_export)
0b26fc7
 int
0b26fc7
 xtab_export_read(void)
0b26fc7
 {
0b26fc7
-	return xtab_read(_PATH_ETAB, _PATH_ETABLCK, 1);
0b26fc7
+	return xtab_read(etab.statefn, etab.lockfn, 1);
0b26fc7
 }
0b26fc7
 
0b26fc7
 /*
0b26fc7
@@ -112,7 +120,7 @@ xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export)
0b26fc7
 int
0b26fc7
 xtab_export_write()
0b26fc7
 {
0b26fc7
-	return xtab_write(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1);
0b26fc7
+	return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1);
0b26fc7
 }
0b26fc7
 
0b26fc7
 /*
0b26fc7
@@ -158,3 +166,74 @@ static void cond_rename(char *newfile, char *oldfile)
0b26fc7
 	rename(newfile, oldfile);
0b26fc7
 	return;
0b26fc7
 }
0b26fc7
+
0b26fc7
+/*
0b26fc7
+ * Returns a dynamically allocated, '\0'-terminated buffer
0b26fc7
+ * containing an appropriate pathname, or NULL if an error
0b26fc7
+ * occurs.  Caller must free the returned result with free(3).
0b26fc7
+ */
0b26fc7
+static char *
0b26fc7
+state_make_pathname(const char *tabname)
0b26fc7
+{
0b26fc7
+	return generic_make_pathname(state_base_dirname, tabname);
0b26fc7
+}
0b26fc7
+
0b26fc7
+/**
0b26fc7
+ * state_setup_basedir - set up basedir
0b26fc7
+ * @progname: C string containing name of program, for error messages
0b26fc7
+ * @parentdir: C string containing pathname to on-disk state, or NULL
0b26fc7
+ *
0b26fc7
+ * This runs before logging is set up, so error messages are directed
0b26fc7
+ * to stderr.
0b26fc7
+ *
0b26fc7
+ * Returns true and sets up our basedir, if @parentdir was valid
0b26fc7
+ * and usable; otherwise false is returned.
0b26fc7
+ */
0b26fc7
+_Bool
0b26fc7
+state_setup_basedir(const char *progname, const char *parentdir)
0b26fc7
+{
0b26fc7
+	return generic_setup_basedir(progname, parentdir, state_base_dirname,
0b26fc7
+				     PATH_MAX);
0b26fc7
+}
0b26fc7
+
0b26fc7
+int
0b26fc7
+setup_state_path_names(const char *progname, const char *statefn,
0b26fc7
+		      const char *tmpfn, const char *lockfn,
0b26fc7
+		      struct state_paths *paths)
0b26fc7
+{
0b26fc7
+	paths->statefn = state_make_pathname(statefn);
0b26fc7
+	if (!paths->statefn) {
0b26fc7
+		fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
0b26fc7
+			progname, statefn);
0b26fc7
+		goto out_err;
0b26fc7
+	}
0b26fc7
+	paths->tmpfn = state_make_pathname(tmpfn);
0b26fc7
+	if (!paths->tmpfn) {
0b26fc7
+		fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
0b26fc7
+			progname, tmpfn);
0b26fc7
+		goto out_free_statefn;
0b26fc7
+	}
0b26fc7
+	paths->lockfn = state_make_pathname(lockfn);
0b26fc7
+	if (!paths->lockfn) {
0b26fc7
+		fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
0b26fc7
+			progname, lockfn);
0b26fc7
+		goto out_free_tmpfn;
0b26fc7
+	}
0b26fc7
+	return 1;
0b26fc7
+
0b26fc7
+out_free_tmpfn:
0b26fc7
+	free(paths->tmpfn);
0b26fc7
+out_free_statefn:
0b26fc7
+	free(paths->statefn);
0b26fc7
+out_err:
0b26fc7
+	return 0;
0b26fc7
+
0b26fc7
+}
0b26fc7
+
0b26fc7
+void
0b26fc7
+free_state_path_names(struct state_paths *paths)
0b26fc7
+{
0b26fc7
+	free(paths->statefn);
0b26fc7
+	free(paths->tmpfn);
0b26fc7
+	free(paths->lockfn);
0b26fc7
+}
0b26fc7
diff --git a/support/include/conffile.h b/support/include/conffile.h
0b26fc7
index 3fe3a78..20b1a32 100644
0b26fc7
--- a/support/include/conffile.h
0b26fc7
+++ b/support/include/conffile.h
0b26fc7
@@ -48,8 +48,6 @@ struct conf_list {
0b26fc7
 	TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields;
0b26fc7
 };
0b26fc7
 
0b26fc7
-extern char    *conf_path;
0b26fc7
-
0b26fc7
 extern int      conf_begin(void);
0b26fc7
 extern int      conf_decode_base64(uint8_t *, uint32_t *, unsigned char *);
0b26fc7
 extern int      conf_end(int, int);
0b26fc7
@@ -61,9 +59,8 @@ extern int      conf_get_num(char *, char *, int);
0b26fc7
 extern _Bool    conf_get_bool(char *, char *, _Bool);
0b26fc7
 extern char    *conf_get_str(char *, char *);
0b26fc7
 extern char    *conf_get_section(char *, char *, char *);
0b26fc7
-extern void     conf_init(void);
0b26fc7
+extern void     conf_init(const char *);
0b26fc7
 extern int      conf_match_num(char *, char *, int);
0b26fc7
-extern void     conf_reinit(void);
0b26fc7
 extern int      conf_remove(int, char *, char *);
0b26fc7
 extern int      conf_remove_section(int, char *);
0b26fc7
 extern void     conf_report(void);
0b26fc7
diff --git a/support/include/misc.h b/support/include/misc.h
0b26fc7
index eedc1fe..06e2a0c 100644
0b26fc7
--- a/support/include/misc.h
0b26fc7
+++ b/support/include/misc.h
0b26fc7
@@ -15,6 +15,9 @@
0b26fc7
 int	randomkey(unsigned char *keyout, int len);
0b26fc7
 int	weakrandomkey(unsigned char *keyout, int len);
0b26fc7
 
0b26fc7
+char *generic_make_pathname(const char *, const char *);
0b26fc7
+_Bool generic_setup_basedir(const char *, const char *, char *, const size_t);
0b26fc7
+
0b26fc7
 extern int is_mountpoint(char *path);
0b26fc7
 
0b26fc7
 /* size of the file pointer buffers for rpc procfs files */
0b26fc7
diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h
0b26fc7
index 15ecc6b..7933ff5 100644
0b26fc7
--- a/support/include/nfs/nfs.h
0b26fc7
+++ b/support/include/nfs/nfs.h
0b26fc7
@@ -16,8 +16,8 @@
0b26fc7
 #define NFSD_MINVERS 2
0b26fc7
 #define NFSD_MAXVERS 4
0b26fc7
 
0b26fc7
-#define NFS4_MINMINOR 1
0b26fc7
-#define NFS4_MAXMINOR WORD_BIT
0b26fc7
+#define NFS4_MINMINOR 0
0b26fc7
+#define NFS4_MAXMINOR (WORD_BIT-1)
0b26fc7
 
0b26fc7
 struct nfs_fh_len {
0b26fc7
 	int		fh_size;
0b26fc7
@@ -27,21 +27,24 @@ struct nfs_fh_len {
0b26fc7
 
0b26fc7
 #define NFSCTL_UDPBIT		      (1 << (17 - 1))
0b26fc7
 #define NFSCTL_TCPBIT		      (1 << (18 - 1))
0b26fc7
+#define NFSCTL_PROTODEFAULT	      (NFSCTL_TCPBIT)
0b26fc7
 
0b26fc7
 #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) 
0b26fc7
+#define NFSCTL_MINORUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v)))
0b26fc7
 #define NFSCTL_UDPUNSET(_cltbits)     ((_cltbits) &= ~NFSCTL_UDPBIT) 
0b26fc7
 #define NFSCTL_TCPUNSET(_cltbits)     ((_cltbits) &= ~NFSCTL_TCPBIT) 
0b26fc7
 
0b26fc7
 #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) 
0b26fc7
+#define NFSCTL_MINORISSET(_cltbits, _v) ((_cltbits) & (1 << (_v)))
0b26fc7
 #define NFSCTL_UDPISSET(_cltbits)     ((_cltbits) & NFSCTL_UDPBIT) 
0b26fc7
 #define NFSCTL_TCPISSET(_cltbits)     ((_cltbits) & NFSCTL_TCPBIT) 
0b26fc7
 
0b26fc7
 #define NFSCTL_VERDEFAULT (0xc)       /* versions 3 and 4 */
0b26fc7
 #define NFSCTL_VERSET(_cltbits, _v)   ((_cltbits) |= (1 << ((_v) - 1))) 
0b26fc7
+#define NFSCTL_MINORSET(_cltbits, _v)   ((_cltbits) |= (1 << (_v)))
0b26fc7
 #define NFSCTL_UDPSET(_cltbits)       ((_cltbits) |= NFSCTL_UDPBIT)
0b26fc7
 #define NFSCTL_TCPSET(_cltbits)       ((_cltbits) |= NFSCTL_TCPBIT)
0b26fc7
 
0b26fc7
 #define NFSCTL_ANYPROTO(_cltbits)     ((_cltbits) & (NFSCTL_UDPBIT | NFSCTL_TCPBIT))
0b26fc7
-#define NFSCTL_ALLBITS (~0)
0b26fc7
 
0b26fc7
 #endif /* _NFS_NFS_H */
0b26fc7
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
0b26fc7
index 1498977..ab8b2bf 100644
0b26fc7
--- a/support/include/nfslib.h
0b26fc7
+++ b/support/include/nfslib.h
0b26fc7
@@ -35,29 +35,24 @@
0b26fc7
 #ifndef _PATH_IDMAPDCONF
0b26fc7
 #define _PATH_IDMAPDCONF	"/etc/idmapd.conf"
0b26fc7
 #endif
0b26fc7
-#ifndef _PATH_ETAB
0b26fc7
-#define _PATH_ETAB		NFS_STATEDIR "/etab"
0b26fc7
-#endif
0b26fc7
-#ifndef _PATH_ETABTMP
0b26fc7
-#define _PATH_ETABTMP		NFS_STATEDIR "/etab.tmp"
0b26fc7
-#endif
0b26fc7
-#ifndef _PATH_ETABLCK
0b26fc7
-#define _PATH_ETABLCK		NFS_STATEDIR "/.etab.lock"
0b26fc7
-#endif
0b26fc7
-#ifndef _PATH_RMTAB
0b26fc7
-#define _PATH_RMTAB		NFS_STATEDIR "/rmtab"
0b26fc7
-#endif
0b26fc7
-#ifndef _PATH_RMTABTMP
0b26fc7
-#define _PATH_RMTABTMP		_PATH_RMTAB ".tmp"
0b26fc7
-#endif
0b26fc7
-#ifndef _PATH_RMTABLCK
0b26fc7
-#define _PATH_RMTABLCK		NFS_STATEDIR "/.rmtab.lock"
0b26fc7
-#endif
0b26fc7
 #ifndef _PATH_PROC_EXPORTS
0b26fc7
 #define	_PATH_PROC_EXPORTS	"/proc/fs/nfs/exports"
0b26fc7
 #define	_PATH_PROC_EXPORTS_ALT	"/proc/fs/nfsd/exports"
0b26fc7
 #endif
0b26fc7
 
0b26fc7
+#define ETAB		"etab"
0b26fc7
+#define ETABTMP		"etab.tmp"
0b26fc7
+#define ETABLCK 	".etab.lock"
0b26fc7
+#define RMTAB		"rmtab"
0b26fc7
+#define RMTABTMP	"rmtab.tmp"
0b26fc7
+#define RMTABLCK	".rmtab.lock"
0b26fc7
+
0b26fc7
+struct state_paths {
0b26fc7
+	char *statefn;
0b26fc7
+	char *tmpfn;
0b26fc7
+	char *lockfn;
0b26fc7
+};
0b26fc7
+
0b26fc7
 /* Maximum number of security flavors on an export: */
0b26fc7
 #define SECFLAVOR_COUNT 8
0b26fc7
 
0b26fc7
@@ -120,6 +115,10 @@ void			fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos);
0b26fc7
 void			fendrmtabent(FILE *fp);
0b26fc7
 void			frewindrmtabent(FILE *fp);
0b26fc7
 
0b26fc7
+_Bool state_setup_basedir(const char *, const char *);
0b26fc7
+int setup_state_path_names(const char *, const char *, const char *, const char *, struct state_paths *);
0b26fc7
+void free_state_path_names(struct state_paths *);
0b26fc7
+
0b26fc7
 /* mydaemon */
0b26fc7
 void daemon_init(bool fg);
0b26fc7
 void daemon_ready(void);
0b26fc7
diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am
0b26fc7
index 1048580..8936b0d 100644
0b26fc7
--- a/support/misc/Makefile.am
0b26fc7
+++ b/support/misc/Makefile.am
0b26fc7
@@ -1,6 +1,6 @@
0b26fc7
 ## Process this file with automake to produce Makefile.in
0b26fc7
 
0b26fc7
 noinst_LIBRARIES = libmisc.a
0b26fc7
-libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c
0b26fc7
+libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c
0b26fc7
 
0b26fc7
 MAINTAINERCLEANFILES = Makefile.in
0b26fc7
diff --git a/support/misc/file.c b/support/misc/file.c
0b26fc7
new file mode 100644
0b26fc7
index 0000000..63597df
0b26fc7
--- /dev/null
0b26fc7
+++ b/support/misc/file.c
0b26fc7
@@ -0,0 +1,110 @@
0b26fc7
+/*
0b26fc7
+ * Copyright 2009 Oracle.  All rights reserved.
0b26fc7
+ * Copyright 2017 Red Hat, Inc.  All rights reserved.
0b26fc7
+ *
0b26fc7
+ * This file is part of nfs-utils.
0b26fc7
+ *
0b26fc7
+ * nfs-utils is free software; you can redistribute it and/or modify
0b26fc7
+ * it under the terms of the GNU General Public License as published by
0b26fc7
+ * the Free Software Foundation; either version 2 of the License, or
0b26fc7
+ * (at your option) any later version.
0b26fc7
+ *
0b26fc7
+ * nfs-utils is distributed in the hope that it will be useful,
0b26fc7
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
0b26fc7
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0b26fc7
+ * GNU General Public License for more details.
0b26fc7
+ *
0b26fc7
+ * You should have received a copy of the GNU General Public License
0b26fc7
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
0b26fc7
+ */
0b26fc7
+
0b26fc7
+#include <sys/stat.h>
0b26fc7
+
0b26fc7
+#include <string.h>
0b26fc7
+#include <libgen.h>
0b26fc7
+#include <stdio.h>
0b26fc7
+#include <errno.h>
0b26fc7
+#include <dirent.h>
0b26fc7
+#include <stdlib.h>
0b26fc7
+#include <stdbool.h>
0b26fc7
+
0b26fc7
+#include "xlog.h"
0b26fc7
+#include "misc.h"
0b26fc7
+
0b26fc7
+/*
0b26fc7
+ * Returns a dynamically allocated, '\0'-terminated buffer
0b26fc7
+ * containing an appropriate pathname, or NULL if an error
0b26fc7
+ * occurs.  Caller must free the returned result with free(3).
0b26fc7
+ */
0b26fc7
+__attribute__((__malloc__))
0b26fc7
+char *
0b26fc7
+generic_make_pathname(const char *base, const char *leaf)
0b26fc7
+{
0b26fc7
+	size_t size;
0b26fc7
+	char *path;
0b26fc7
+	int len;
0b26fc7
+
0b26fc7
+	size = strlen(base) + strlen(leaf) + 2;
0b26fc7
+	if (size > PATH_MAX)
0b26fc7
+		return NULL;
0b26fc7
+
0b26fc7
+	path = malloc(size);
0b26fc7
+	if (path == NULL)
0b26fc7
+		return NULL;
0b26fc7
+
0b26fc7
+	len = snprintf(path, size, "%s/%s", base, leaf);
0b26fc7
+	if ((len < 0) || ((size_t)len >= size)) {
0b26fc7
+		free(path);
0b26fc7
+		return NULL;
0b26fc7
+	}
0b26fc7
+
0b26fc7
+	return path;
0b26fc7
+}
0b26fc7
+
0b26fc7
+
0b26fc7
+/**
0b26fc7
+ * generic_setup_basedir - set up basedir
0b26fc7
+ * @progname: C string containing name of program, for error messages
0b26fc7
+ * @parentdir: C string containing pathname to on-disk state, or NULL
0b26fc7
+ * @base: character buffer to contain the basedir that is set up
0b26fc7
+ * @baselen: size of @base in bytes
0b26fc7
+ *
0b26fc7
+ * This runs before logging is set up, so error messages are directed
0b26fc7
+ * to stderr.
0b26fc7
+ *
0b26fc7
+ * Returns true and sets up our basedir, if @parentdir was valid
0b26fc7
+ * and usable; otherwise false is returned.
0b26fc7
+ */
0b26fc7
+_Bool
0b26fc7
+generic_setup_basedir(const char *progname, const char *parentdir, char *base,
0b26fc7
+		      const size_t baselen)
0b26fc7
+{
0b26fc7
+	static char buf[PATH_MAX];
0b26fc7
+	struct stat st;
0b26fc7
+	char *path;
0b26fc7
+
0b26fc7
+	/* First: test length of name and whether it exists */
0b26fc7
+	if ((strlen(parentdir) >= baselen) || (strlen(parentdir) >= PATH_MAX)) {
0b26fc7
+		(void)fprintf(stderr, "%s: Directory name too long: %s",
0b26fc7
+				progname, parentdir);
0b26fc7
+		return false;
0b26fc7
+	}
0b26fc7
+	if (lstat(parentdir, &st) == -1) {
0b26fc7
+		(void)fprintf(stderr, "%s: Failed to stat %s: %s",
0b26fc7
+				progname, parentdir, strerror(errno));
0b26fc7
+		return false;
0b26fc7
+	}
0b26fc7
+
0b26fc7
+	/* Ensure we have a clean directory pathname */
0b26fc7
+	strncpy(buf, parentdir, sizeof(buf));
0b26fc7
+	path = dirname(buf);
0b26fc7
+	if (*path == '.') {
0b26fc7
+		(void)fprintf(stderr, "%s: Unusable directory %s",
0b26fc7
+				progname, parentdir);
0b26fc7
+		return false;
0b26fc7
+	}
0b26fc7
+
0b26fc7
+	xlog(D_CALL, "Using %s as the state directory", parentdir);
0b26fc7
+	strcpy(base, parentdir);
0b26fc7
+	return true;
0b26fc7
+}
0b26fc7
diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
0b26fc7
index e5e2579..9912afa 100644
0b26fc7
--- a/support/nfs/cacheio.c
0b26fc7
+++ b/support/nfs/cacheio.c
0b26fc7
@@ -27,6 +27,8 @@
0b26fc7
 #include <time.h>
0b26fc7
 #include <errno.h>
0b26fc7
 
0b26fc7
+extern struct state_paths etab;
0b26fc7
+
0b26fc7
 void qword_add(char **bpp, int *lp, char *str)
0b26fc7
 {
0b26fc7
 	char *bp = *bpp;
0b26fc7
@@ -199,7 +201,7 @@ int qword_get_uint(char **bpp, unsigned int *anint)
0b26fc7
 }
0b26fc7
 
0b26fc7
 /* flush the kNFSd caches.
0b26fc7
- * Set the flush time to the mtime of _PATH_ETAB or
0b26fc7
+ * Set the flush time to the mtime of the etab state file or
0b26fc7
  * if force, to now.
0b26fc7
  * the caches to flush are:
0b26fc7
  *  auth.unix.ip nfsd.export nfsd.fh
0b26fc7
@@ -228,7 +230,7 @@ cache_flush(int force)
0b26fc7
 	};
0b26fc7
 	now = time(0);
0b26fc7
 	if (force ||
0b26fc7
-	    stat(_PATH_ETAB, &stb) != 0 ||
0b26fc7
+	    stat(etab.statefn, &stb) != 0 ||
0b26fc7
 	    stb.st_mtime > now)
0b26fc7
 		stb.st_mtime = time(0);
0b26fc7
 	
0b26fc7
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
0b26fc7
index e717c1e..efbdc8b 100644
0b26fc7
--- a/support/nfs/conffile.c
0b26fc7
+++ b/support/nfs/conffile.c
0b26fc7
@@ -30,6 +30,10 @@
0b26fc7
  * This code was written under funding by Ericsson Radio Systems.
0b26fc7
  */
0b26fc7
 
0b26fc7
+#ifdef HAVE_CONFIG_H
0b26fc7
+#include <config.h>
0b26fc7
+#endif
0b26fc7
+
0b26fc7
 #include <sys/param.h>
0b26fc7
 #include <sys/mman.h>
0b26fc7
 #include <sys/socket.h>
0b26fc7
@@ -52,7 +56,7 @@
0b26fc7
 #pragma GCC visibility push(hidden)
0b26fc7
 
0b26fc7
 static void conf_load_defaults(void);
0b26fc7
-static int conf_load(int trans, char *path);
0b26fc7
+static int conf_load(int trans, const char *path);
0b26fc7
 static int conf_set(int , char *, char *, char *, 
0b26fc7
 	char *, int , int );
0b26fc7
 
0b26fc7
@@ -73,8 +77,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue;
0b26fc7
 /*
0b26fc7
  * Radix-64 Encoding.
0b26fc7
  */
0b26fc7
+#if 0
0b26fc7
 static const uint8_t bin2asc[]
0b26fc7
   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
0b26fc7
+#endif
0b26fc7
 
0b26fc7
 static const uint8_t asc2bin[] =
0b26fc7
 {
0b26fc7
@@ -105,7 +111,6 @@ struct conf_binding {
0b26fc7
   int is_default;
0b26fc7
 };
0b26fc7
 
0b26fc7
-char *conf_path;
0b26fc7
 LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256];
0b26fc7
 
0b26fc7
 static __inline__ uint8_t
0b26fc7
@@ -369,20 +374,8 @@ conf_load_defaults(void)
0b26fc7
 	return;
0b26fc7
 }
0b26fc7
 
0b26fc7
-void
0b26fc7
-conf_init (void)
0b26fc7
-{
0b26fc7
-	unsigned int i;
0b26fc7
-
0b26fc7
-	for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
0b26fc7
-		LIST_INIT (&conf_bindings[i]);
0b26fc7
-
0b26fc7
-	TAILQ_INIT (&conf_trans_queue);
0b26fc7
-	conf_reinit();
0b26fc7
-}
0b26fc7
-
0b26fc7
 static int
0b26fc7
-conf_load(int trans, char *path)
0b26fc7
+conf_load(int trans, const char *path)
0b26fc7
 {
0b26fc7
 	struct stat sb;
0b26fc7
 	if ((stat (path, &sb) == 0) || (errno != ENOENT)) {
0b26fc7
@@ -421,15 +414,15 @@ conf_load(int trans, char *path)
0b26fc7
 }
0b26fc7
 
0b26fc7
 /* Open the config file and map it into our address space, then parse it.  */
0b26fc7
-void
0b26fc7
-conf_reinit(void)
0b26fc7
+static void
0b26fc7
+conf_reinit(const char *conf_file)
0b26fc7
 {
0b26fc7
 	struct conf_binding *cb = 0;
0b26fc7
 	int trans;
0b26fc7
 	unsigned int i;
0b26fc7
 
0b26fc7
 	trans = conf_begin();
0b26fc7
-	if (conf_load(trans, conf_path) < 0)
0b26fc7
+	if (conf_load(trans, conf_file) < 0)
0b26fc7
 		return;
0b26fc7
 
0b26fc7
 	/* Load default configuration values.  */
0b26fc7
@@ -446,6 +439,20 @@ conf_reinit(void)
0b26fc7
 	return;
0b26fc7
 }
0b26fc7
 
0b26fc7
+void
0b26fc7
+conf_init (const char *conf_file)
0b26fc7
+{
0b26fc7
+	unsigned int i;
0b26fc7
+
0b26fc7
+	for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
0b26fc7
+		LIST_INIT (&conf_bindings[i]);
0b26fc7
+
0b26fc7
+	TAILQ_INIT (&conf_trans_queue);
0b26fc7
+
0b26fc7
+	if (conf_file == NULL) conf_file=NFS_CONFFILE;
0b26fc7
+	conf_reinit(conf_file);
0b26fc7
+}
0b26fc7
+
0b26fc7
 /*
0b26fc7
  * Return the numeric value denoted by TAG in section SECTION or DEF
0b26fc7
  * if that tag does not exist.
0b26fc7
@@ -533,7 +540,7 @@ retry:
0b26fc7
 				 * or from environment
0b26fc7
 				 */
0b26fc7
 				char *env = getenv(cb->value+1);
0b26fc7
-				if (env)
0b26fc7
+				if (env && *env)
0b26fc7
 					return env;
0b26fc7
 				section = "environment";
0b26fc7
 				tag = cb->value + 1;
0b26fc7
diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c
0b26fc7
index 59dfbdf..2ecb2cc 100644
0b26fc7
--- a/support/nfs/rmtab.c
0b26fc7
+++ b/support/nfs/rmtab.c
0b26fc7
@@ -33,12 +33,14 @@
0b26fc7
 
0b26fc7
 static FILE	*rmfp = NULL;
0b26fc7
 
0b26fc7
+extern struct state_paths rmtab;
0b26fc7
+
0b26fc7
 int
0b26fc7
 setrmtabent(char *type)
0b26fc7
 {
0b26fc7
 	if (rmfp)
0b26fc7
 		fclose(rmfp);
0b26fc7
-	rmfp = fsetrmtabent(_PATH_RMTAB, type);
0b26fc7
+	rmfp = fsetrmtabent(rmtab.statefn, type);
0b26fc7
 	return (rmfp != NULL);
0b26fc7
 }
0b26fc7
 
0b26fc7
diff --git a/support/nsm/file.c b/support/nsm/file.c
0b26fc7
index aafa755..52f5401 100644
0b26fc7
--- a/support/nsm/file.c
0b26fc7
+++ b/support/nsm/file.c
0b26fc7
@@ -88,6 +88,7 @@
0b26fc7
 
0b26fc7
 #include "xlog.h"
0b26fc7
 #include "nsm.h"
0b26fc7
+#include "misc.h"
0b26fc7
 
0b26fc7
 #define RPCARGSLEN	(4 * (8 + 1))
0b26fc7
 #define LINELEN		(RPCARGSLEN + SM_PRIV_SIZE * 2 + 1)
0b26fc7
@@ -170,25 +171,7 @@ __attribute__((__malloc__))
0b26fc7
 static char *
0b26fc7
 nsm_make_pathname(const char *directory)
0b26fc7
 {
0b26fc7
-	size_t size;
0b26fc7
-	char *path;
0b26fc7
-	int len;
0b26fc7
-
0b26fc7
-	size = strlen(nsm_base_dirname) + strlen(directory) + 2;
0b26fc7
-	if (size > PATH_MAX)
0b26fc7
-		return NULL;
0b26fc7
-
0b26fc7
-	path = malloc(size);
0b26fc7
-	if (path == NULL)
0b26fc7
-		return NULL;
0b26fc7
-
0b26fc7
-	len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory);
0b26fc7
-	if (error_check(len, size)) {
0b26fc7
-		free(path);
0b26fc7
-		return NULL;
0b26fc7
-	}
0b26fc7
-
0b26fc7
-	return path;
0b26fc7
+	return generic_make_pathname(nsm_base_dirname, directory);
0b26fc7
 }
0b26fc7
 
0b26fc7
 /*
0b26fc7
@@ -293,29 +276,8 @@ out:
0b26fc7
 _Bool
0b26fc7
 nsm_setup_pathnames(const char *progname, const char *parentdir)
0b26fc7
 {
0b26fc7
-	static char buf[PATH_MAX];
0b26fc7
-	struct stat st;
0b26fc7
-	char *path;
0b26fc7
-
0b26fc7
-	/* First: test length of name and whether it exists */
0b26fc7
-	if (lstat(parentdir, &st) == -1) {
0b26fc7
-		(void)fprintf(stderr, "%s: Failed to stat %s: %s",
0b26fc7
-				progname, parentdir, strerror(errno));
0b26fc7
-		return false;
0b26fc7
-	}
0b26fc7
-
0b26fc7
-	/* Ensure we have a clean directory pathname */
0b26fc7
-	strncpy(buf, parentdir, sizeof(buf));
0b26fc7
-	path = dirname(buf);
0b26fc7
-	if (*path == '.') {
0b26fc7
-		(void)fprintf(stderr, "%s: Unusable directory %s",
0b26fc7
-				progname, parentdir);
0b26fc7
-		return false;
0b26fc7
-	}
0b26fc7
-
0b26fc7
-	xlog(D_CALL, "Using %s as the state directory", parentdir);
0b26fc7
-	strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname));
0b26fc7
-	return true;
0b26fc7
+	return generic_setup_basedir(progname, parentdir, nsm_base_dirname,
0b26fc7
+				     PATH_MAX);
0b26fc7
 }
0b26fc7
 
0b26fc7
 /**
0b26fc7
diff --git a/systemd/Makefile.am b/systemd/Makefile.am
0b26fc7
index 0d15b9f..eef53c4 100644
0b26fc7
--- a/systemd/Makefile.am
0b26fc7
+++ b/systemd/Makefile.am
0b26fc7
@@ -4,6 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in
0b26fc7
 
0b26fc7
 unit_files =  \
0b26fc7
     nfs-client.target \
0b26fc7
+    rpc_pipefs.target \
0b26fc7
     \
0b26fc7
     nfs-mountd.service \
0b26fc7
     nfs-server.service \
0b26fc7
@@ -42,14 +43,23 @@ EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS)
0b26fc7
 unit_dir = /usr/lib/systemd/system
0b26fc7
 generator_dir = /usr/lib/systemd/system-generators
0b26fc7
 
0b26fc7
-EXTRA_PROGRAMS	= nfs-server-generator
0b26fc7
+EXTRA_PROGRAMS	= nfs-server-generator rpc-pipefs-generator
0b26fc7
 genexecdir = $(generator_dir)
0b26fc7
+
0b26fc7
+COMMON_SRCS = systemd.c systemd.h
0b26fc7
+
0b26fc7
+nfs_server_generator_SOURCES = $(COMMON_SRCS) nfs-server-generator.c
0b26fc7
+
0b26fc7
+rpc_pipefs_generator_SOURCES = $(COMMON_SRCS) rpc-pipefs-generator.c
0b26fc7
+
0b26fc7
 nfs_server_generator_LDADD = ../support/export/libexport.a \
0b26fc7
 			     ../support/nfs/libnfs.a \
0b26fc7
 			     ../support/misc/libmisc.a
0b26fc7
 
0b26fc7
+rpc_pipefs_generator_LDADD = ../support/nfs/libnfs.a
0b26fc7
+
0b26fc7
 if INSTALL_SYSTEMD
0b26fc7
-genexec_PROGRAMS = nfs-server-generator
0b26fc7
+genexec_PROGRAMS = nfs-server-generator rpc-pipefs-generator
0b26fc7
 install-data-hook: $(unit_files)
0b26fc7
 	mkdir -p $(DESTDIR)/$(unitdir)
0b26fc7
 	cp $(unit_files) $(DESTDIR)/$(unitdir)
0b26fc7
diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service
0b26fc7
index ddc324e..2bbcee6 100644
0b26fc7
--- a/systemd/nfs-blkmap.service
0b26fc7
+++ b/systemd/nfs-blkmap.service
0b26fc7
@@ -2,8 +2,8 @@
0b26fc7
 Description=pNFS block layout mapping daemon
0b26fc7
 DefaultDependencies=no
0b26fc7
 Conflicts=umount.target
0b26fc7
-After=var-lib-nfs-rpc_pipefs.mount
0b26fc7
-Requires=var-lib-nfs-rpc_pipefs.mount
0b26fc7
+After=rpc_pipefs.target
0b26fc7
+Requires=rpc_pipefs.target
0b26fc7
 
0b26fc7
 PartOf=nfs-utils.service
0b26fc7
 
0b26fc7
diff --git a/systemd/nfs-idmapd.service b/systemd/nfs-idmapd.service
0b26fc7
index acca86b..f38fe52 100644
0b26fc7
--- a/systemd/nfs-idmapd.service
0b26fc7
+++ b/systemd/nfs-idmapd.service
0b26fc7
@@ -1,8 +1,8 @@
0b26fc7
 [Unit]
0b26fc7
 Description=NFSv4 ID-name mapping service
0b26fc7
 DefaultDependencies=no
0b26fc7
-Requires=var-lib-nfs-rpc_pipefs.mount
0b26fc7
-After=var-lib-nfs-rpc_pipefs.mount local-fs.target
0b26fc7
+Requires=rpc_pipefs.target
0b26fc7
+After=rpc_pipefs.target local-fs.target
0b26fc7
 
0b26fc7
 BindsTo=nfs-server.service
0b26fc7
 
0b26fc7
diff --git a/systemd/nfs-mountd.service b/systemd/nfs-mountd.service
0b26fc7
index 15e828b..e8ece53 100644
0b26fc7
--- a/systemd/nfs-mountd.service
0b26fc7
+++ b/systemd/nfs-mountd.service
0b26fc7
@@ -2,8 +2,10 @@
0b26fc7
 Description=NFS Mount Daemon
0b26fc7
 DefaultDependencies=no
0b26fc7
 Requires=proc-fs-nfsd.mount
0b26fc7
+Wants=network-online.target
0b26fc7
 After=proc-fs-nfsd.mount
0b26fc7
-After=network.target local-fs.target
0b26fc7
+After=network-online.target local-fs.target
0b26fc7
+After=rpcbind.socket
0b26fc7
 BindsTo=nfs-server.service
0b26fc7
 
0b26fc7
 [Service]
0b26fc7
diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c
0b26fc7
index cc99969..737f109 100644
0b26fc7
--- a/systemd/nfs-server-generator.c
0b26fc7
+++ b/systemd/nfs-server-generator.c
0b26fc7
@@ -29,6 +29,7 @@
0b26fc7
 #include "misc.h"
0b26fc7
 #include "nfslib.h"
0b26fc7
 #include "exportfs.h"
0b26fc7
+#include "systemd.h"
0b26fc7
 
0b26fc7
 /* A simple "set of strings" to remove duplicates
0b26fc7
  * found in /etc/exports
0b26fc7
@@ -55,38 +56,31 @@ static int is_unique(struct list **lp, char *path)
0b26fc7
 	return 1;
0b26fc7
 }
0b26fc7
 
0b26fc7
-/* We need to convert a path name to a systemd unit
0b26fc7
- * name.  This requires some translation ('/' -> '-')
0b26fc7
- * and some escaping.
0b26fc7
- */
0b26fc7
-static void systemd_escape(FILE *f, char *path)
0b26fc7
+static int has_noauto_flag(char *path)
0b26fc7
 {
0b26fc7
-	while (*path == '/')
0b26fc7
-		path++;
0b26fc7
-	if (!*path) {
0b26fc7
-		/* "/" becomes "-", otherwise leading "/" is ignored */
0b26fc7
-		fputs("-", f);
0b26fc7
-		return;
0b26fc7
-	}
0b26fc7
-	while (*path) {
0b26fc7
-		char c = *path++;
0b26fc7
-
0b26fc7
-		if (c == '/') {
0b26fc7
-			/* multiple non-trailing slashes become '-' */
0b26fc7
-			while (*path == '/')
0b26fc7
-				path++;
0b26fc7
-			if (*path)
0b26fc7
-				fputs("-", f);
0b26fc7
-		} else if (isalnum(c) || c == ':' || c == '.')
0b26fc7
-			fputc(c, f);
0b26fc7
-		else
0b26fc7
-			fprintf(f, "\\x%02x", c & 0xff);
0b26fc7
+	FILE		*fstab;
0b26fc7
+	struct mntent	*mnt;
0b26fc7
+
0b26fc7
+	fstab = setmntent("/etc/fstab", "r");
0b26fc7
+	if (!fstab)
0b26fc7
+		return 0;
0b26fc7
+
0b26fc7
+	while ((mnt = getmntent(fstab)) != NULL) {
0b26fc7
+		int l = strlen(mnt->mnt_dir);
0b26fc7
+		if (strncmp(mnt->mnt_dir, path, l) != 0)
0b26fc7
+			continue;
0b26fc7
+		if (path[l] && path[l] != '/')
0b26fc7
+			continue;
0b26fc7
+		if (hasmntopt(mnt, "noauto"))
0b26fc7
+			break;
0b26fc7
 	}
0b26fc7
+	fclose(fstab);
0b26fc7
+	return mnt != NULL;
0b26fc7
 }
0b26fc7
 
0b26fc7
 int main(int argc, char *argv[])
0b26fc7
 {
0b26fc7
-	char		*path;
0b26fc7
+	char		*path, *spath;
0b26fc7
 	char		dirbase[] = "/nfs-server.service.d";
0b26fc7
 	char		filebase[] = "/order-with-mounts.conf";
0b26fc7
 	nfs_export	*exp;
0b26fc7
@@ -124,6 +118,10 @@ int main(int argc, char *argv[])
0b26fc7
 		for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
0b26fc7
 			if (!is_unique(&list, exp->m_export.e_path))
0b26fc7
 				continue;
0b26fc7
+			if (exp->m_export.e_mountpoint)
0b26fc7
+				continue;
0b26fc7
+			if (has_noauto_flag(exp->m_export.e_path))
0b26fc7
+				continue;
0b26fc7
 			if (strchr(exp->m_export.e_path, ' '))
0b26fc7
 				fprintf(f, "RequiresMountsFor=\"%s\"\n",
0b26fc7
 					exp->m_export.e_path);
0b26fc7
@@ -141,9 +139,15 @@ int main(int argc, char *argv[])
0b26fc7
 		if (strcmp(mnt->mnt_type, "nfs") != 0 &&
0b26fc7
 		    strcmp(mnt->mnt_type, "nfs4") != 0)
0b26fc7
 			continue;
0b26fc7
-		fprintf(f, "Before= ");
0b26fc7
-		systemd_escape(f, mnt->mnt_dir);
0b26fc7
-		fprintf(f, ".mount\n");
0b26fc7
+
0b26fc7
+		spath = systemd_escape(mnt->mnt_dir, ".mount");
0b26fc7
+		if (!spath) {
0b26fc7
+			fprintf(stderr, 
0b26fc7
+				"nfs-server-generator: convert path failed: %s\n",
0b26fc7
+				mnt->mnt_dir);
0b26fc7
+			continue;
0b26fc7
+		}
0b26fc7
+		fprintf(f, "Before=%s\n", spath);
0b26fc7
 	}
0b26fc7
 
0b26fc7
 	fclose(fstab);
0b26fc7
diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service
0b26fc7
index 5be5de6..136552b 100644
0b26fc7
--- a/systemd/nfs-server.service
0b26fc7
+++ b/systemd/nfs-server.service
0b26fc7
@@ -3,12 +3,12 @@ Description=NFS server and services
0b26fc7
 DefaultDependencies=no
0b26fc7
 Requires= network.target proc-fs-nfsd.mount
0b26fc7
 Requires= nfs-mountd.service
0b26fc7
-Wants=rpcbind.socket
0b26fc7
+Wants=rpcbind.socket network-online.target
0b26fc7
 Wants=rpc-statd.service nfs-idmapd.service
0b26fc7
 Wants=rpc-statd-notify.service
0b26fc7
 
0b26fc7
-After= local-fs.target
0b26fc7
-After= network.target proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
0b26fc7
+After= network-online.target local-fs.target
0b26fc7
+After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
0b26fc7
 After= nfs-idmapd.service rpc-statd.service
0b26fc7
 Before= rpc-statd-notify.service
0b26fc7
 
0b26fc7
diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man
0b26fc7
index 91c49a0..189b052 100644
0b26fc7
--- a/systemd/nfs.conf.man
0b26fc7
+++ b/systemd/nfs.conf.man
0b26fc7
@@ -96,6 +96,18 @@ value, which can be one or more from the list
0b26fc7
 .BR all .
0b26fc7
 When a list is given, the members should be comma-separated.
0b26fc7
 .TP
0b26fc7
+.B general
0b26fc7
+Recognized values:
0b26fc7
+.BR pipefs-directory .
0b26fc7
+
0b26fc7
+See
0b26fc7
+.BR blkmapd (8),
0b26fc7
+.BR rpc.idmapd (8),
0b26fc7
+and
0b26fc7
+.BR rpc.gssd (8)
0b26fc7
+for details.
0b26fc7
+
0b26fc7
+.TP
0b26fc7
 .B nfsdcltrack
0b26fc7
 Recognized values:
0b26fc7
 .BR storagedir .
0b26fc7
@@ -154,6 +166,13 @@ section, are used to configure mountd.  See
0b26fc7
 .BR rpc.mountd (8)
0b26fc7
 for details.
0b26fc7
 
0b26fc7
+The
0b26fc7
+.B state-directory-path
0b26fc7
+value in the
0b26fc7
+.B [mountd]
0b26fc7
+section is also used by
0b26fc7
+.BR exportfs (8).
0b26fc7
+
0b26fc7
 .TP
0b26fc7
 .B statd
0b26fc7
 Recognized values:
0b26fc7
@@ -198,7 +217,6 @@ Recognized values:
0b26fc7
 .BR limit-to-legacy-enctypes ,
0b26fc7
 .BR context-timeout ,
0b26fc7
 .BR rpc-timeout ,
0b26fc7
-.BR pipefs-directory ,
0b26fc7
 .BR keytab-file ,
0b26fc7
 .BR cred-cache-directory ,
0b26fc7
 .BR preferred-realm .
0b26fc7
diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in
0b26fc7
index b353027..6807db3 100644
0b26fc7
--- a/systemd/rpc-gssd.service.in
0b26fc7
+++ b/systemd/rpc-gssd.service.in
0b26fc7
@@ -2,8 +2,8 @@
0b26fc7
 Description=RPC security service for NFS client and server
0b26fc7
 DefaultDependencies=no
0b26fc7
 Conflicts=umount.target
0b26fc7
-Requires=var-lib-nfs-rpc_pipefs.mount
0b26fc7
-After=var-lib-nfs-rpc_pipefs.mount
0b26fc7
+Requires=rpc_pipefs.target
0b26fc7
+After=rpc_pipefs.target
0b26fc7
 
0b26fc7
 ConditionPathExists=@_sysconfdir@/krb5.keytab
0b26fc7
 
0b26fc7
diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c
0b26fc7
new file mode 100644
0b26fc7
index 0000000..59eee87
0b26fc7
--- /dev/null
0b26fc7
+++ b/systemd/rpc-pipefs-generator.c
0b26fc7
@@ -0,0 +1,137 @@
0b26fc7
+/*
0b26fc7
+ * rpc-pipefs-generator:
0b26fc7
+ *   systemd generator to create ordering dependencies between
0b26fc7
+ *   nfs services and the rpc_pipefs mountpoint
0b26fc7
+ */
0b26fc7
+
0b26fc7
+#ifdef HAVE_CONFIG_H
0b26fc7
+#include <config.h>
0b26fc7
+#endif
0b26fc7
+
0b26fc7
+#include <sys/stat.h>
0b26fc7
+#include <sys/types.h>
0b26fc7
+#include <unistd.h>
0b26fc7
+#include <stdlib.h>
0b26fc7
+#include <string.h>
0b26fc7
+#include <ctype.h>
0b26fc7
+#include <stdio.h>
0b26fc7
+#include <mntent.h>
0b26fc7
+
0b26fc7
+#include "nfslib.h"
0b26fc7
+#include "conffile.h"
0b26fc7
+#include "systemd.h"
0b26fc7
+
0b26fc7
+#define RPC_PIPEFS_DEFAULT "/var/lib/nfs/rpc_pipefs"
0b26fc7
+
0b26fc7
+static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit,
0b26fc7
+			       const char *dirname)
0b26fc7
+{
0b26fc7
+	char	*path;
0b26fc7
+	FILE	*f;
0b26fc7
+
0b26fc7
+	path = malloc(strlen(dirname) + 1 + strlen(pipefs_unit));
0b26fc7
+	if (!path)
0b26fc7
+		return 1;
0b26fc7
+	sprintf(path, "%s/%s", dirname, pipefs_unit);
0b26fc7
+	f = fopen(path, "w");
0b26fc7
+	if (!f)
0b26fc7
+		return 1;
0b26fc7
+
0b26fc7
+	fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n");
0b26fc7
+	fprintf(f, "Description=RPC Pipe File System\n");
0b26fc7
+	fprintf(f, "DefaultDependencies=no\n");
0b26fc7
+	fprintf(f, "After=systemd-tmpfiles-setup.service\n");
0b26fc7
+	fprintf(f, "Conflicts=umount.target\n");
0b26fc7
+	fprintf(f, "\n[Mount]\n");
0b26fc7
+	fprintf(f, "What=sunrpc\n");
0b26fc7
+	fprintf(f, "Where=%s\n", pipefs_path);
0b26fc7
+	fprintf(f, "Type=rpc_pipefs\n");
0b26fc7
+
0b26fc7
+	fclose(f);
0b26fc7
+	return 0;
0b26fc7
+}
0b26fc7
+
0b26fc7
+static
0b26fc7
+int generate_target(char *pipefs_path, const char *dirname)
0b26fc7
+{
0b26fc7
+	char	*path;
0b26fc7
+	char	filebase[] = "/rpc_pipefs.target";
0b26fc7
+	char	*pipefs_unit;
0b26fc7
+	FILE	*f;
0b26fc7
+	int 	ret = 0;
0b26fc7
+
0b26fc7
+	pipefs_unit = systemd_escape(pipefs_path, ".mount");
0b26fc7
+	if (!pipefs_unit)
0b26fc7
+		return 1;
0b26fc7
+
0b26fc7
+	ret = generate_mount_unit(pipefs_path, pipefs_unit, dirname);
0b26fc7
+	if (ret)
0b26fc7
+		return ret;
0b26fc7
+
0b26fc7
+	path = malloc(strlen(dirname) + 1 + sizeof(filebase));
0b26fc7
+	if (!path)
0b26fc7
+		return 2;
0b26fc7
+	sprintf(path, "%s", dirname);
0b26fc7
+	mkdir(path, 0755);
0b26fc7
+	strcat(path, filebase);
0b26fc7
+	f = fopen(path, "w");
0b26fc7
+	if (!f)
0b26fc7
+		return 1;
0b26fc7
+
0b26fc7
+	fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n");
0b26fc7
+	fprintf(f, "Requires=%s\n", pipefs_unit);
0b26fc7
+	fprintf(f, "After=%s\n", pipefs_unit);
0b26fc7
+	fclose(f);
0b26fc7
+
0b26fc7
+	return 0;
0b26fc7
+}
0b26fc7
+
0b26fc7
+static int is_non_pipefs_mountpoint(char *path)
0b26fc7
+{
0b26fc7
+	FILE		*mtab;
0b26fc7
+	struct mntent	*mnt;
0b26fc7
+
0b26fc7
+	mtab = setmntent("/etc/mtab", "r");
0b26fc7
+	if (!mtab)
0b26fc7
+		return 0;
0b26fc7
+
0b26fc7
+	while ((mnt = getmntent(mtab)) != NULL) {
0b26fc7
+		if (strlen(mnt->mnt_dir) != strlen(path))
0b26fc7
+			continue;
0b26fc7
+		if (strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir)))
0b26fc7
+			continue;
0b26fc7
+		if (strncmp(mnt->mnt_type, "rpc_pipefs", strlen(mnt->mnt_type)))
0b26fc7
+			break;
0b26fc7
+	}
0b26fc7
+	fclose(mtab);
0b26fc7
+	return mnt != NULL;
0b26fc7
+}
0b26fc7
+
0b26fc7
+int main(int argc, char *argv[])
0b26fc7
+{
0b26fc7
+	int 	ret;
0b26fc7
+	char	*s;
0b26fc7
+
0b26fc7
+	/* Avoid using any external services */
0b26fc7
+	xlog_syslog(0);
0b26fc7
+
0b26fc7
+	if (argc != 4 || argv[1][0] != '/') {
0b26fc7
+		fprintf(stderr, "rpc-pipefs-generator: create systemd dependencies for nfs services\n");
0b26fc7
+		fprintf(stderr, "Usage: normal-dir early-dir late-dir\n");
0b26fc7
+		exit(1);
0b26fc7
+	}
0b26fc7
+
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
+	s = conf_get_str("general", "pipefs-directory");
0b26fc7
+	if (!s)
0b26fc7
+		exit(0);
0b26fc7
+	if (strlen(s) == strlen(RPC_PIPEFS_DEFAULT) &&
0b26fc7
+			strcmp(s, RPC_PIPEFS_DEFAULT) == 0)
0b26fc7
+		exit(0);
0b26fc7
+
0b26fc7
+	if (is_non_pipefs_mountpoint(s))
0b26fc7
+		exit(1);
0b26fc7
+
0b26fc7
+	ret = generate_target(s, argv[1]);
0b26fc7
+	exit(ret);
0b26fc7
+}
0b26fc7
diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service
0b26fc7
index 7bfc9b1..687fe31 100644
0b26fc7
--- a/systemd/rpc-statd-notify.service
0b26fc7
+++ b/systemd/rpc-statd-notify.service
0b26fc7
@@ -1,8 +1,8 @@
0b26fc7
 [Unit]
0b26fc7
 Description=Notify NFS peers of a restart
0b26fc7
 DefaultDependencies=no
0b26fc7
-Requires=network.target
0b26fc7
-After=local-fs.target network.target nss-lookup.target
0b26fc7
+Wants=network-online.target
0b26fc7
+After=local-fs.target network-online.target nss-lookup.target
0b26fc7
 
0b26fc7
 # if we run an nfs server, it needs to be running before we
0b26fc7
 # tell clients that it has restarted.
0b26fc7
diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service
0b26fc7
index 60d600f..f41ae20 100644
0b26fc7
--- a/systemd/rpc-statd.service
0b26fc7
+++ b/systemd/rpc-statd.service
0b26fc7
@@ -3,7 +3,8 @@ Description=NFS status monitor for NFSv2/3 locking.
0b26fc7
 DefaultDependencies=no
0b26fc7
 Conflicts=umount.target
0b26fc7
 Requires=nss-lookup.target rpcbind.socket
0b26fc7
-After=network.target nss-lookup.target rpcbind.socket
0b26fc7
+Wants=network-online.target
0b26fc7
+After=network-online.target nss-lookup.target rpcbind.socket
0b26fc7
 
0b26fc7
 PartOf=nfs-utils.service
0b26fc7
 
0b26fc7
diff --git a/systemd/rpc-svcgssd.service b/systemd/rpc-svcgssd.service
0b26fc7
index 7187e3c..cb2bcd4 100644
0b26fc7
--- a/systemd/rpc-svcgssd.service
0b26fc7
+++ b/systemd/rpc-svcgssd.service
0b26fc7
@@ -1,8 +1,7 @@
0b26fc7
 [Unit]
0b26fc7
 Description=RPC security service for NFS server
0b26fc7
 DefaultDependencies=no
0b26fc7
-Requires=var-lib-nfs-rpc_pipefs.mount
0b26fc7
-After=var-lib-nfs-rpc_pipefs.mount local-fs.target
0b26fc7
+After=local-fs.target
0b26fc7
 PartOf=nfs-server.service
0b26fc7
 PartOf=nfs-utils.service
0b26fc7
 
0b26fc7
diff --git a/systemd/rpc_pipefs.target b/systemd/rpc_pipefs.target
0b26fc7
new file mode 100644
0b26fc7
index 0000000..01d4d27
0b26fc7
--- /dev/null
0b26fc7
+++ b/systemd/rpc_pipefs.target
0b26fc7
@@ -0,0 +1,3 @@
0b26fc7
+[Unit]
0b26fc7
+Requires=var-lib-nfs-rpc_pipefs.mount
0b26fc7
+After=var-lib-nfs-rpc_pipefs.mount
0b26fc7
diff --git a/systemd/systemd.c b/systemd/systemd.c
0b26fc7
new file mode 100644
0b26fc7
index 0000000..17820d4
0b26fc7
--- /dev/null
0b26fc7
+++ b/systemd/systemd.c
0b26fc7
@@ -0,0 +1,133 @@
0b26fc7
+/*
0b26fc7
+ * Helper functions for systemd generators in nfs-utils.
0b26fc7
+ *
0b26fc7
+ * Currently just systemd_escape().
0b26fc7
+ */
0b26fc7
+
0b26fc7
+#include <stdio.h>
0b26fc7
+#include <stdlib.h>
0b26fc7
+#include <ctype.h>
0b26fc7
+#include <string.h>
0b26fc7
+
0b26fc7
+static const char hex[16] =
0b26fc7
+{
0b26fc7
+  '0', '1', '2', '3', '4', '5', '6', '7',
0b26fc7
+  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
0b26fc7
+};
0b26fc7
+
0b26fc7
+/*
0b26fc7
+ * determine length of the string that systemd_escape() needs to allocate
0b26fc7
+ */
0b26fc7
+static int systemd_len(char *path)
0b26fc7
+{
0b26fc7
+	char *p;
0b26fc7
+	int len = 0;
0b26fc7
+
0b26fc7
+	p = path;
0b26fc7
+	while (*p == '/')
0b26fc7
+		/* multiple leading "/" are ignored */
0b26fc7
+		p++;
0b26fc7
+
0b26fc7
+	if (!*p)
0b26fc7
+		/* root directory "/" becomes is encoded as a single "-" */
0b26fc7
+		return 1;
0b26fc7
+
0b26fc7
+	if (*p == '.')
0b26fc7
+		/*
0b26fc7
+		 * replace "." with "\x2d" escape sequence if
0b26fc7
+		 * it's the first character in escaped path
0b26fc7
+		 * */
0b26fc7
+		len += 4;
0b26fc7
+
0b26fc7
+	while (*p) {
0b26fc7
+		unsigned char c = *p++;
0b26fc7
+
0b26fc7
+		if (c == '/') {
0b26fc7
+			/* multiple non-trailing slashes become '-' */
0b26fc7
+			while (*p == '/')
0b26fc7
+				p++;
0b26fc7
+			if (*p)
0b26fc7
+				len++;
0b26fc7
+		} else if (isalnum(c) || c == ':' || c == '.' || c == '_')
0b26fc7
+			/* these characters are not replaced */
0b26fc7
+			len++;
0b26fc7
+		else
0b26fc7
+			/* replace with "\x2d" escape sequence */
0b26fc7
+			len += 4;
0b26fc7
+	}
0b26fc7
+
0b26fc7
+	return len;
0b26fc7
+}
0b26fc7
+
0b26fc7
+/*
0b26fc7
+ * convert c to "\x2d" escape sequence and append to string
0b26fc7
+ * at position p, advancing p
0b26fc7
+ */
0b26fc7
+static char *hexify(unsigned char c, char *p)
0b26fc7
+{
0b26fc7
+	*p++ = '\\';
0b26fc7
+	*p++ = 'x';
0b26fc7
+	*p++ = hex[c >> 4];
0b26fc7
+	*p++ = hex[c & 0xf];
0b26fc7
+	return p;
0b26fc7
+}
0b26fc7
+
0b26fc7
+/*
0b26fc7
+ * convert a path to a unit name according to the logic in systemd.unit(5):
0b26fc7
+ *
0b26fc7
+ *     Basically, given a path, "/" is replaced by "-", and all other
0b26fc7
+ *     characters which are not ASCII alphanumerics are replaced by C-style
0b26fc7
+ *     "\x2d" escapes (except that "_" is never replaced and "." is only
0b26fc7
+ *     replaced when it would be the first character in the escaped path).
0b26fc7
+ *     The root directory "/" is encoded as single dash, while otherwise the
0b26fc7
+ *     initial and ending "/" are removed from all paths during
0b26fc7
+ *     transformation.
0b26fc7
+ *
0b26fc7
+ * NB: Although the systemd.unit(5) doesn't mention it, the ':' character
0b26fc7
+ * is not escaped.
0b26fc7
+ */
0b26fc7
+char *systemd_escape(char *path, char *suffix)
0b26fc7
+{
0b26fc7
+	char *result;
0b26fc7
+	char *p;
0b26fc7
+	int len;
0b26fc7
+
0b26fc7
+	len = systemd_len(path);
0b26fc7
+	result = malloc(len + strlen(suffix) + 1);
0b26fc7
+	p = result;
0b26fc7
+	while (*path == '/')
0b26fc7
+		/* multiple leading "/" are ignored */
0b26fc7
+		path++;
0b26fc7
+	if (!*path) {
0b26fc7
+		/* root directory "/" becomes is encoded as a single "-" */
0b26fc7
+		*p++ = '-';
0b26fc7
+		goto out;
0b26fc7
+	}
0b26fc7
+	if (*path == '.')
0b26fc7
+		/*
0b26fc7
+		 * replace "." with "\x2d" escape sequence if
0b26fc7
+		 * it's the first character in escaped path
0b26fc7
+		 * */
0b26fc7
+		p = hexify(*path++, p);
0b26fc7
+
0b26fc7
+	while (*path) {
0b26fc7
+		unsigned char c = *path++;
0b26fc7
+
0b26fc7
+		if (c == '/') {
0b26fc7
+			/* multiple non-trailing slashes become '-' */
0b26fc7
+			while (*path == '/')
0b26fc7
+				path++;
0b26fc7
+			if (*path)
0b26fc7
+				*p++ = '-';
0b26fc7
+		} else if (isalnum(c) || c == ':' || c == '.' || c == '_')
0b26fc7
+			/* these characters are not replaced */
0b26fc7
+			*p++ = c;
0b26fc7
+		else
0b26fc7
+			/* replace with "\x2d" escape sequence */
0b26fc7
+			p = hexify(c, p);
0b26fc7
+	}
0b26fc7
+
0b26fc7
+out:
0b26fc7
+	sprintf(p, "%s", suffix);
0b26fc7
+	return result;
0b26fc7
+}
0b26fc7
diff --git a/systemd/systemd.h b/systemd/systemd.h
0b26fc7
new file mode 100644
0b26fc7
index 0000000..25235ec
0b26fc7
--- /dev/null
0b26fc7
+++ b/systemd/systemd.h
0b26fc7
@@ -0,0 +1,6 @@
0b26fc7
+#ifndef SYSTEMD_H
0b26fc7
+#define SYSTEMD_H
0b26fc7
+
0b26fc7
+char *systemd_escape(char *path, char *suffix);
0b26fc7
+
0b26fc7
+#endif /* SYSTEMD_H */
0b26fc7
diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man
0b26fc7
index 914b80f..4b3d3f0 100644
0b26fc7
--- a/utils/blkmapd/blkmapd.man
0b26fc7
+++ b/utils/blkmapd/blkmapd.man
0b26fc7
@@ -43,9 +43,24 @@ Performs device discovery only then exits.
0b26fc7
 Runs
0b26fc7
 .B blkmapd
0b26fc7
 in the foreground and sends output to stderr (as opposed to syslogd)
0b26fc7
+.SH CONFIGURATION FILE
0b26fc7
+The
0b26fc7
+.B blkmapd
0b26fc7
+daemon recognizes the following value from the
0b26fc7
+.B [general]
0b26fc7
+section of the
0b26fc7
+.I /etc/nfs.conf
0b26fc7
+configuration file:
0b26fc7
+.TP
0b26fc7
+.B pipefs-directory
0b26fc7
+Tells
0b26fc7
+.B blkmapd
0b26fc7
+where to look for the rpc_pipefs filesystem.  The default value is
0b26fc7
+.IR /var/lib/nfs/rpc_pipefs .
0b26fc7
 .SH SEE ALSO
0b26fc7
 .BR nfs (5),
0b26fc7
-.BR dmsetup (8)
0b26fc7
+.BR dmsetup (8),
0b26fc7
+.BR nfs.conf (5)
0b26fc7
 .sp
0b26fc7
 RFC 5661 for the NFS version 4.1 specification.
0b26fc7
 .br
0b26fc7
diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c
0b26fc7
index 8eb3fd0..c66669d 100644
0b26fc7
--- a/utils/blkmapd/device-discovery.c
0b26fc7
+++ b/utils/blkmapd/device-discovery.c
0b26fc7
@@ -50,21 +50,36 @@
0b26fc7
 #include <errno.h>
0b26fc7
 #include <libdevmapper.h>
0b26fc7
 
0b26fc7
+#ifdef HAVE_CONFIG_H
0b26fc7
+#include "config.h"
0b26fc7
+#endif /* HAVE_CONFIG_H */
0b26fc7
+
0b26fc7
 #include "device-discovery.h"
0b26fc7
 #include "xcommon.h"
0b26fc7
+#include "nfslib.h"
0b26fc7
+#include "conffile.h"
0b26fc7
 
0b26fc7
 #define EVENT_SIZE (sizeof(struct inotify_event))
0b26fc7
 #define EVENT_BUFSIZE (1024 * EVENT_SIZE)
0b26fc7
 
0b26fc7
-#define BL_PIPE_FILE	"/var/lib/nfs/rpc_pipefs/nfs/blocklayout"
0b26fc7
-#define NFSPIPE_DIR	"/var/lib/nfs/rpc_pipefs/nfs"
0b26fc7
 #define RPCPIPE_DIR	"/var/lib/nfs/rpc_pipefs"
0b26fc7
 #define PID_FILE	"/var/run/blkmapd.pid"
0b26fc7
 
0b26fc7
+#define CONF_SAVE(w, f) do {			\
0b26fc7
+	char *p = f;				\
0b26fc7
+	if (p != NULL)				\
0b26fc7
+		(w) = p;			\
0b26fc7
+} while (0)
0b26fc7
+
0b26fc7
+static char bl_pipe_file[PATH_MAX];
0b26fc7
+static char nfspipe_dir[PATH_MAX];
0b26fc7
+static char rpcpipe_dir[PATH_MAX];
0b26fc7
+
0b26fc7
 struct bl_disk *visible_disk_list;
0b26fc7
 int    bl_watch_fd, bl_pipe_fd, nfs_pipedir_wfd, rpc_pipedir_wfd;
0b26fc7
 int    pidfd = -1;
0b26fc7
 
0b26fc7
+
0b26fc7
 struct bl_disk_path *bl_get_path(const char *filepath,
0b26fc7
 				 struct bl_disk_path *paths)
0b26fc7
 {
0b26fc7
@@ -358,8 +373,8 @@ static void bl_rpcpipe_cb(void)
0b26fc7
 				continue;
0b26fc7
 			if (event->mask & IN_CREATE) {
0b26fc7
 				BL_LOG_WARNING("nfs pipe dir created\n");
0b26fc7
-				bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd);
0b26fc7
-				bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
0b26fc7
+				bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd);
0b26fc7
+				bl_pipe_fd = open(bl_pipe_file, O_RDWR);
0b26fc7
 			} else if (event->mask & IN_DELETE) {
0b26fc7
 				BL_LOG_WARNING("nfs pipe dir deleted\n");
0b26fc7
 				inotify_rm_watch(bl_watch_fd, nfs_pipedir_wfd);
0b26fc7
@@ -372,7 +387,7 @@ static void bl_rpcpipe_cb(void)
0b26fc7
 				continue;
0b26fc7
 			if (event->mask & IN_CREATE) {
0b26fc7
 				BL_LOG_WARNING("blocklayout pipe file created\n");
0b26fc7
-				bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
0b26fc7
+				bl_pipe_fd = open(bl_pipe_file, O_RDWR);
0b26fc7
 				if (bl_pipe_fd < 0)
0b26fc7
 					BL_LOG_ERR("open %s failed: %s\n",
0b26fc7
 						event->name, strerror(errno));
0b26fc7
@@ -437,6 +452,18 @@ int main(int argc, char **argv)
0b26fc7
 {
0b26fc7
 	int opt, dflag = 0, fg = 0, ret = 1;
0b26fc7
 	char pidbuf[64];
0b26fc7
+	char *xrpcpipe_dir = NULL;
0b26fc7
+
0b26fc7
+	strncpy(rpcpipe_dir, RPCPIPE_DIR, sizeof(rpcpipe_dir));
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
+	CONF_SAVE(xrpcpipe_dir, conf_get_str("general", "pipefs-directory"));
0b26fc7
+	if (xrpcpipe_dir != NULL)
0b26fc7
+		strlcpy(rpcpipe_dir, xrpcpipe_dir, sizeof(rpcpipe_dir));
0b26fc7
+
0b26fc7
+	strncpy(nfspipe_dir, rpcpipe_dir, sizeof(nfspipe_dir));
0b26fc7
+	strlcat(nfspipe_dir, "/nfs", sizeof(nfspipe_dir));
0b26fc7
+	strncpy(bl_pipe_file, rpcpipe_dir, sizeof(bl_pipe_file));
0b26fc7
+	strlcat(bl_pipe_file, "/nfs/blocklayout", sizeof(bl_pipe_file));
0b26fc7
 
0b26fc7
 	while ((opt = getopt(argc, argv, "hdf")) != -1) {
0b26fc7
 		switch (opt) {
0b26fc7
@@ -496,12 +523,12 @@ int main(int argc, char **argv)
0b26fc7
 	}
0b26fc7
 
0b26fc7
 	/* open pipe file */
0b26fc7
-	bl_watch_dir(RPCPIPE_DIR, &rpc_pipedir_wfd);
0b26fc7
-	bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd);
0b26fc7
+	bl_watch_dir(rpcpipe_dir, &rpc_pipedir_wfd);
0b26fc7
+	bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd);
0b26fc7
 
0b26fc7
-	bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
0b26fc7
+	bl_pipe_fd = open(bl_pipe_file, O_RDWR);
0b26fc7
 	if (bl_pipe_fd < 0)
0b26fc7
-		BL_LOG_ERR("open pipe file %s failed: %s\n", BL_PIPE_FILE, strerror(errno));
0b26fc7
+		BL_LOG_ERR("open pipe file %s failed: %s\n", bl_pipe_file, strerror(errno));
0b26fc7
 
0b26fc7
 	while (1) {
0b26fc7
 		/* discover device when needed */
0b26fc7
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
0b26fc7
index 61dddfb..beed1b3 100644
0b26fc7
--- a/utils/exportfs/exportfs.c
0b26fc7
+++ b/utils/exportfs/exportfs.c
0b26fc7
@@ -50,7 +50,8 @@ static void release_lockfile(void);
0b26fc7
 
0b26fc7
 static const char *lockfile = EXP_LOCKFILE;
0b26fc7
 static int _lockfd = -1;
0b26fc7
-char *conf_path = NFS_CONFFILE;
0b26fc7
+
0b26fc7
+struct state_paths etab;
0b26fc7
 
0b26fc7
 /*
0b26fc7
  * If we aren't careful, changes made by exportfs can be lost
0b26fc7
@@ -95,6 +96,7 @@ main(int argc, char **argv)
0b26fc7
 	int	f_ignore = 0;
0b26fc7
 	int	i, c;
0b26fc7
 	int	force_flush = 0;
0b26fc7
+	char	*s;
0b26fc7
 
0b26fc7
 	if ((progname = strrchr(argv[0], '/')) != NULL)
0b26fc7
 		progname++;
0b26fc7
@@ -105,9 +107,14 @@ main(int argc, char **argv)
0b26fc7
 	xlog_stderr(1);
0b26fc7
 	xlog_syslog(0);
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
 	xlog_from_conffile("exportfs");
0b26fc7
 
0b26fc7
+	/* NOTE: following uses "mountd" section of nfs.conf !!!! */
0b26fc7
+	s = conf_get_str("mountd", "state-directory-path");
0b26fc7
+	if (s && !state_setup_basedir(argv[0], s))
0b26fc7
+		exit(1);
0b26fc7
+
0b26fc7
 	while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) {
0b26fc7
 		switch(c) {
0b26fc7
 		case 'a':
0b26fc7
@@ -159,13 +166,17 @@ main(int argc, char **argv)
0b26fc7
 		xlog(L_ERROR, "-r and -u are incompatible");
0b26fc7
 		return 1;
0b26fc7
 	}
0b26fc7
+	if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
0b26fc7
+		return 1;
0b26fc7
 	if (optind == argc && ! f_all) {
0b26fc7
 		if (force_flush) {
0b26fc7
 			cache_flush(1);
0b26fc7
+			free_state_path_names(&etab;;
0b26fc7
 			return 0;
0b26fc7
 		} else {
0b26fc7
 			xtab_export_read();
0b26fc7
 			dump(f_verbose, f_export_format);
0b26fc7
+			free_state_path_names(&etab;;
0b26fc7
 			return 0;
0b26fc7
 		}
0b26fc7
 	}
0b26fc7
@@ -206,6 +217,7 @@ main(int argc, char **argv)
0b26fc7
 	}
0b26fc7
 	xtab_export_write();
0b26fc7
 	cache_flush(force_flush);
0b26fc7
+	free_state_path_names(&etab;;
0b26fc7
 
0b26fc7
 	return export_errno;
0b26fc7
 }
0b26fc7
diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
0b26fc7
index 45b6d83..91d3589 100644
0b26fc7
--- a/utils/exportfs/exportfs.man
0b26fc7
+++ b/utils/exportfs/exportfs.man
0b26fc7
@@ -148,6 +148,29 @@ options.
0b26fc7
 .TP
0b26fc7
 .B -s
0b26fc7
 Display the current export list suitable for /etc/exports.
0b26fc7
+
0b26fc7
+.SH CONFIGURATION FILE
0b26fc7
+The
0b26fc7
+.B [exportfs]
0b26fc7
+section of the
0b26fc7
+.I /etc/nfs.conf
0b26fc7
+configuration file can contain a
0b26fc7
+.B debug
0b26fc7
+value, which can be one or more from the list
0b26fc7
+.BR general ,
0b26fc7
+.BR call ,
0b26fc7
+.BR auth ,
0b26fc7
+.BR parse ,
0b26fc7
+.BR all .
0b26fc7
+When a list is given, the members should be comma-separated.
0b26fc7
+
0b26fc7
+.B exportfs
0b26fc7
+will also recognize the
0b26fc7
+.B state-directory-path
0b26fc7
+value from the
0b26fc7
+.B [mountd]
0b26fc7
+section.
0b26fc7
+
0b26fc7
 .SH DISCUSSION
0b26fc7
 .SS Exporting Directories
0b26fc7
 The first synopsis shows how to invoke
0b26fc7
diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man
0b26fc7
index 0c516fa..9efa29f 100644
0b26fc7
--- a/utils/exportfs/nfsd.man
0b26fc7
+++ b/utils/exportfs/nfsd.man
0b26fc7
@@ -105,11 +105,6 @@ clients have for different filesystems.
0b26fc7
 The caches are:
0b26fc7
 
0b26fc7
 .TP
0b26fc7
-.B auth.domain
0b26fc7
-This cache maps the name of a client (or domain) to an internal data
0b26fc7
-structure.  The only access that is possible is to flush the cache.
0b26fc7
-
0b26fc7
-.TP
0b26fc7
 .B auth.unix.ip
0b26fc7
 This cache contains a mapping from IP address to the name of the
0b26fc7
 authentication domain that the ipaddress should be treated as part of.
0b26fc7
@@ -133,7 +128,8 @@ are:
0b26fc7
 .B flush
0b26fc7
 When a number of seconds since epoch (1 Jan 1970) is written to this
0b26fc7
 file, all entries in the cache that were last updated before that file
0b26fc7
-become invalidated and will be flushed out.  Writing 1 will flush
0b26fc7
+become invalidated and will be flushed out.  Writing a time in the
0b26fc7
+future (in seconds since epoch) will flush
0b26fc7
 everything.  This is the only file that will always be present.
0b26fc7
 
0b26fc7
 .TP
0b26fc7
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
0b26fc7
index 4d18d35..053a223 100644
0b26fc7
--- a/utils/gssd/gssd.c
0b26fc7
+++ b/utils/gssd/gssd.c
0b26fc7
@@ -79,7 +79,6 @@ static int pipefs_fd;
0b26fc7
 static int inotify_fd;
0b26fc7
 struct event inotify_ev;
0b26fc7
 
0b26fc7
-char *conf_path = NFS_CONFFILE;
0b26fc7
 char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE;
0b26fc7
 char **ccachesearch;
0b26fc7
 int  use_memcache = 0;
0b26fc7
@@ -87,6 +86,7 @@ int  root_uses_machine_creds = 1;
0b26fc7
 unsigned int  context_timeout = 0;
0b26fc7
 unsigned int  rpc_timeout = 5;
0b26fc7
 char *preferred_realm = NULL;
0b26fc7
+char *ccachedir = NULL;
0b26fc7
 /* Avoid DNS reverse lookups on server names */
0b26fc7
 static bool avoid_dns = true;
0b26fc7
 int thread_started = false;
0b26fc7
@@ -837,21 +837,12 @@ usage(char *progname)
0b26fc7
 	exit(1);
0b26fc7
 }
0b26fc7
 
0b26fc7
-int
0b26fc7
-main(int argc, char *argv[])
0b26fc7
+inline static void 
0b26fc7
+read_gss_conf(void)
0b26fc7
 {
0b26fc7
-	int fg = 0;
0b26fc7
-	int verbosity = 0;
0b26fc7
-	int rpc_verbosity = 0;
0b26fc7
-	int opt;
0b26fc7
-	int i;
0b26fc7
-	extern char *optarg;
0b26fc7
-	char *progname;
0b26fc7
-	char *ccachedir = NULL;
0b26fc7
-	struct event sighup_ev;
0b26fc7
 	char *s;
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
 	use_memcache = conf_get_bool("gssd", "use-memcache", use_memcache);
0b26fc7
 	root_uses_machine_creds = conf_get_bool("gssd", "use-machine-creds",
0b26fc7
 						root_uses_machine_creds);
0b26fc7
@@ -865,6 +856,10 @@ main(int argc, char *argv[])
0b26fc7
 	s = conf_get_str("gssd", "pipefs-directory");
0b26fc7
 	if (!s)
0b26fc7
 		s = conf_get_str("general", "pipefs-directory");
0b26fc7
+	else
0b26fc7
+		printerr(0, "WARNING: Specifying pipefs-directory in the [gssd] "
0b26fc7
+			 "section of %s is deprecated.  Use the [general] "
0b26fc7
+			 "section instead.", NFS_CONFFILE);
0b26fc7
 	if (s)
0b26fc7
 		pipefs_path = s;
0b26fc7
 	s = conf_get_str("gssd", "keytab-file");
0b26fc7
@@ -877,6 +872,22 @@ main(int argc, char *argv[])
0b26fc7
 	if (s)
0b26fc7
 		preferred_realm = s;
0b26fc7
 
0b26fc7
+}
0b26fc7
+
0b26fc7
+int
0b26fc7
+main(int argc, char *argv[])
0b26fc7
+{
0b26fc7
+	int fg = 0;
0b26fc7
+	int verbosity = 0;
0b26fc7
+	int rpc_verbosity = 0;
0b26fc7
+	int opt;
0b26fc7
+	int i;
0b26fc7
+	extern char *optarg;
0b26fc7
+	char *progname;
0b26fc7
+	struct event sighup_ev;
0b26fc7
+
0b26fc7
+	read_gss_conf();
0b26fc7
+
0b26fc7
 	while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) {
0b26fc7
 		switch (opt) {
0b26fc7
 			case 'f':
0b26fc7
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
0b26fc7
index 87eef02..e620f0d 100644
0b26fc7
--- a/utils/gssd/gssd.man
0b26fc7
+++ b/utils/gssd/gssd.man
0b26fc7
@@ -335,10 +335,6 @@ Equivalent to
0b26fc7
 Equivalent to
0b26fc7
 .BR -t .
0b26fc7
 .TP
0b26fc7
-.B pipefs-directory
0b26fc7
-Equivalent to
0b26fc7
-.BR -p .
0b26fc7
-.TP
0b26fc7
 .B keytab-file
0b26fc7
 Equivalent to
0b26fc7
 .BR -k .
0b26fc7
@@ -350,6 +346,14 @@ Equivalent to
0b26fc7
 .B preferred-realm
0b26fc7
 Equivalent to
0b26fc7
 .BR -R .
0b26fc7
+.P
0b26fc7
+In addtion, the following value is recognized from the
0b26fc7
+.B [general]
0b26fc7
+section:
0b26fc7
+.TP
0b26fc7
+.B pipefs-directory
0b26fc7
+Equivalent to
0b26fc7
+.BR -p .
0b26fc7
 
0b26fc7
 .SH SEE ALSO
0b26fc7
 .BR rpc.svcgssd (8),
0b26fc7
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
0b26fc7
index d74d372..4fc81c3 100644
0b26fc7
--- a/utils/gssd/gssd_proc.c
0b26fc7
+++ b/utils/gssd/gssd_proc.c
0b26fc7
@@ -729,10 +729,18 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
0b26fc7
 	char			*target = NULL;
0b26fc7
 	char			*service = NULL;
0b26fc7
 	char			*enctypes = NULL;
0b26fc7
+	char			*upcall_str;
0b26fc7
+	char			*pbuf = info->lbuf;
0b26fc7
 
0b26fc7
 	printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
0b26fc7
 
0b26fc7
-	for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) {
0b26fc7
+	upcall_str = strdup(info->lbuf);
0b26fc7
+	if (upcall_str == NULL) {
0b26fc7
+		printerr(0, "ERROR: malloc failure\n");
0b26fc7
+		goto out_nomem;
0b26fc7
+	}
0b26fc7
+
0b26fc7
+	while ((p = strsep(&pbuf, " "))) {
0b26fc7
 		if (!strncmp(p, "mech=", strlen("mech=")))
0b26fc7
 			mech = p + strlen("mech=");
0b26fc7
 		else if (!strncmp(p, "uid=", strlen("uid=")))
0b26fc7
@@ -748,7 +756,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
0b26fc7
 	if (!mech || strlen(mech) < 1) {
0b26fc7
 		printerr(0, "WARNING: handle_gssd_upcall: "
0b26fc7
 			    "failed to find gss mechanism name "
0b26fc7
-			    "in upcall string '%s'\n", info->lbuf);
0b26fc7
+			    "in upcall string '%s'\n", upcall_str);
0b26fc7
 		goto out;
0b26fc7
 	}
0b26fc7
 
0b26fc7
@@ -761,7 +769,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
0b26fc7
 	if (!uidstr) {
0b26fc7
 		printerr(0, "WARNING: handle_gssd_upcall: "
0b26fc7
 			    "failed to find uid "
0b26fc7
-			    "in upcall string '%s'\n", info->lbuf);
0b26fc7
+			    "in upcall string '%s'\n", upcall_str);
0b26fc7
 		goto out;
0b26fc7
 	}
0b26fc7
 
0b26fc7
@@ -774,7 +782,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
0b26fc7
 	if (target && strlen(target) < 1) {
0b26fc7
 		printerr(0, "WARNING: handle_gssd_upcall: "
0b26fc7
 			 "failed to parse target name "
0b26fc7
-			 "in upcall string '%s'\n", info->lbuf);
0b26fc7
+			 "in upcall string '%s'\n", upcall_str);
0b26fc7
 		goto out;
0b26fc7
 	}
0b26fc7
 
0b26fc7
@@ -789,7 +797,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
0b26fc7
 	if (service && strlen(service) < 1) {
0b26fc7
 		printerr(0, "WARNING: handle_gssd_upcall: "
0b26fc7
 			 "failed to parse service type "
0b26fc7
-			 "in upcall string '%s'\n", info->lbuf);
0b26fc7
+			 "in upcall string '%s'\n", upcall_str);
0b26fc7
 		goto out;
0b26fc7
 	}
0b26fc7
 
0b26fc7
@@ -802,6 +810,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
0b26fc7
 		do_error_downcall(clp->gssd_fd, uid, -EACCES);
0b26fc7
 	}
0b26fc7
 out:
0b26fc7
+	free(upcall_str);
0b26fc7
+out_nomem:
0b26fc7
 	free(info);
0b26fc7
 	return;
0b26fc7
 }
0b26fc7
diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c
0b26fc7
index 1fb579a..3514ae1 100644
0b26fc7
--- a/utils/gssd/svcgssd.c
0b26fc7
+++ b/utils/gssd/svcgssd.c
0b26fc7
@@ -63,8 +63,6 @@
0b26fc7
 #include "err_util.h"
0b26fc7
 #include "conffile.h"
0b26fc7
 
0b26fc7
-char *conf_path = NFS_CONFFILE;
0b26fc7
-
0b26fc7
 void
0b26fc7
 sig_die(int signal)
0b26fc7
 {
0b26fc7
@@ -103,7 +101,7 @@ main(int argc, char *argv[])
0b26fc7
 	char *principal = NULL;
0b26fc7
 	char *s;
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE); 
0b26fc7
 
0b26fc7
 	s = conf_get_str("svcgssd", "principal");
0b26fc7
 	if (!s)
0b26fc7
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
0b26fc7
index f4e083a..c12e878 100644
0b26fc7
--- a/utils/idmapd/idmapd.c
0b26fc7
+++ b/utils/idmapd/idmapd.c
0b26fc7
@@ -165,9 +165,6 @@ static char *nobodyuser, *nobodygroup;
0b26fc7
 static uid_t nobodyuid;
0b26fc7
 static gid_t nobodygid;
0b26fc7
 
0b26fc7
-/* Used by conffile.c in libnfs.a */
0b26fc7
-char *conf_path;
0b26fc7
-
0b26fc7
 static int
0b26fc7
 flush_nfsd_cache(char *path, time_t now)
0b26fc7
 {
0b26fc7
@@ -219,8 +216,8 @@ main(int argc, char **argv)
0b26fc7
 	int serverstart = 1, clientstart = 1;
0b26fc7
 	int ret;
0b26fc7
 	char *progname;
0b26fc7
+	char *conf_path = NULL;
0b26fc7
 
0b26fc7
-	conf_path = _PATH_IDMAPDCONF;
0b26fc7
 	nobodyuser = NFS4NOBODY_USER;
0b26fc7
 	nobodygroup = NFS4NOBODY_GROUP;
0b26fc7
 	strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir));
0b26fc7
@@ -234,8 +231,11 @@ main(int argc, char **argv)
0b26fc7
 #define GETOPTSTR "hvfd:p:U:G:c:CS"
0b26fc7
 	opterr=0; /* Turn off error messages */
0b26fc7
 	while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) {
0b26fc7
-		if (opt == 'c')
0b26fc7
+		if (opt == 'c') {
0b26fc7
+			warnx("-c is deprecated and may be removed in the "
0b26fc7
+			      "future.  See idmapd(8).");
0b26fc7
 			conf_path = optarg;
0b26fc7
+		}
0b26fc7
 		if (opt == '?') {
0b26fc7
 			if (strchr(GETOPTSTR, optopt))
0b26fc7
 				warnx("'-%c' option requires an argument.", optopt);
0b26fc7
@@ -247,17 +247,33 @@ main(int argc, char **argv)
0b26fc7
 	}
0b26fc7
 	optind = 1;
0b26fc7
 
0b26fc7
-	if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) {
0b26fc7
-		warn("Skipping configuration file \"%s\"", conf_path);
0b26fc7
-		conf_path = NULL;
0b26fc7
+	if (conf_path) { /* deprecated -c option was specified */
0b26fc7
+		if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) {
0b26fc7
+			warn("Skipping configuration file \"%s\"", conf_path);
0b26fc7
+			conf_path = NULL;
0b26fc7
+		} else {
0b26fc7
+			conf_init(conf_path);
0b26fc7
+			verbose = conf_get_num("General", "Verbosity", 0);
0b26fc7
+			cache_entry_expiration = conf_get_num("General",
0b26fc7
+					"Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY);
0b26fc7
+			CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory"));
0b26fc7
+			if (xpipefsdir != NULL)
0b26fc7
+				strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir));
0b26fc7
+			CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User"));
0b26fc7
+			CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group"));
0b26fc7
+		}
0b26fc7
 	} else {
0b26fc7
-		conf_init();
0b26fc7
-		verbose = conf_get_num("General", "Verbosity", 0);
0b26fc7
-		cache_entry_expiration = conf_get_num("General",
0b26fc7
-				"Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY);
0b26fc7
+		conf_path = NFS_CONFFILE;
0b26fc7
+		conf_init(conf_path);
0b26fc7
 		CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory"));
0b26fc7
 		if (xpipefsdir != NULL)
0b26fc7
 			strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir));
0b26fc7
+
0b26fc7
+		conf_path = _PATH_IDMAPDCONF;
0b26fc7
+		conf_init(conf_path);
0b26fc7
+		verbose = conf_get_num("General", "Verbosity", 0);
0b26fc7
+		cache_entry_expiration = conf_get_num("General",
0b26fc7
+				"cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY);
0b26fc7
 		CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User"));
0b26fc7
 		CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group"));
0b26fc7
 	}
0b26fc7
diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man
0b26fc7
index d4ab894..5f34d2b 100644
0b26fc7
--- a/utils/idmapd/idmapd.man
0b26fc7
+++ b/utils/idmapd/idmapd.man
0b26fc7
@@ -73,11 +73,28 @@ The default value is \&"/var/lib/nfs/rpc_pipefs\&".
0b26fc7
 .It Fl c Ar path
0b26fc7
 Use configuration file
0b26fc7
 .Ar path .
0b26fc7
+This option is deprecated.
0b26fc7
 .It Fl C
0b26fc7
 Client-only: perform no idmapping for any NFS server, even if one is detected.
0b26fc7
 .It Fl S
0b26fc7
 Server-only: perform no idmapping for any NFS client, even if one is detected.
0b26fc7
 .El
0b26fc7
+.Sh CONFIGURATION FILES
0b26fc7
+.Nm
0b26fc7
+recognizes the following value from the
0b26fc7
+.Sy [general]
0b26fc7
+section of the
0b26fc7
+.Pa /etc/nfs.conf
0b26fc7
+configuration file:
0b26fc7
+.Bl -tag -width Ds_imagedir
0b26fc7
+.It Sy pipefs-directory
0b26fc7
+Equivalent to
0b26fc7
+.Sy -p .
0b26fc7
+.El
0b26fc7
+.Pp
0b26fc7
+All other settings related to id mapping are found in the
0b26fc7
+.Pa /etc/idmapd.conf
0b26fc7
+configuration file.
0b26fc7
 .Sh EXAMPLES
0b26fc7
 .Cm rpc.idmapd -f -vvv
0b26fc7
 .Pp
0b26fc7
@@ -94,9 +111,11 @@ messages to console, and with a verbosity level of 3.
0b26fc7
 .\" This next request is for sections 1, 6, 7 & 8 only.
0b26fc7
 .\" .Sh ENVIRONMENT
0b26fc7
 .Sh FILES
0b26fc7
-.Pa /etc/idmapd.conf
0b26fc7
+.Pa /etc/idmapd.conf ,
0b26fc7
+.Pa /etc/nfs.conf
0b26fc7
 .Sh SEE ALSO
0b26fc7
 .Xr idmapd.conf 5 ,
0b26fc7
+.Xr nfs.conf 5 ,
0b26fc7
 .Xr nfsidmap 8
0b26fc7
 .\".Sh SEE ALSO
0b26fc7
 .\".Xr nylon.conf 4
0b26fc7
diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
0b26fc7
index 0a4cc04..dc964c7 100644
0b26fc7
--- a/utils/mount/configfile.c
0b26fc7
+++ b/utils/mount/configfile.c
0b26fc7
@@ -51,10 +51,6 @@
0b26fc7
 #define NFSMOUNT_SERVER "Server"
0b26fc7
 #endif
0b26fc7
 
0b26fc7
-#ifndef MOUNTOPTS_CONFFILE
0b26fc7
-#define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf"
0b26fc7
-#endif
0b26fc7
-char *conf_path = MOUNTOPTS_CONFFILE;
0b26fc7
 enum {
0b26fc7
 	MNT_NOARG=0,
0b26fc7
 	MNT_INTARG,
0b26fc7
diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h
0b26fc7
index 69ffd1e..e4f8511 100644
0b26fc7
--- a/utils/mount/mount_config.h
0b26fc7
+++ b/utils/mount/mount_config.h
0b26fc7
@@ -20,6 +20,10 @@
0b26fc7
 #include "conffile.h"
0b26fc7
 #include "xlog.h"
0b26fc7
 
0b26fc7
+#ifndef MOUNTOPTS_CONFFILE
0b26fc7
+#define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf"
0b26fc7
+#endif
0b26fc7
+
0b26fc7
 extern char *conf_get_mntopts(char *, char *, char *);
0b26fc7
 
0b26fc7
 static inline void mount_config_init(char *program)
0b26fc7
@@ -28,7 +32,7 @@ static inline void mount_config_init(char *program)
0b26fc7
 	/*
0b26fc7
 	 * Read the the default mount options
0b26fc7
 	 */
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(MOUNTOPTS_CONFFILE);
0b26fc7
 }
0b26fc7
 
0b26fc7
 static inline char *mount_config_opts(char *spec,
0b26fc7
diff --git a/utils/mount/network.c b/utils/mount/network.c
0b26fc7
index 7dceb2d..281e935 100644
0b26fc7
--- a/utils/mount/network.c
0b26fc7
+++ b/utils/mount/network.c
0b26fc7
@@ -33,6 +33,7 @@
0b26fc7
 #include <errno.h>
0b26fc7
 #include <netdb.h>
0b26fc7
 #include <time.h>
0b26fc7
+#include <grp.h>
0b26fc7
 
0b26fc7
 #include <sys/types.h>
0b26fc7
 #include <sys/socket.h>
0b26fc7
@@ -804,6 +805,7 @@ int start_statd(void)
0b26fc7
 			pid_t pid = fork();
0b26fc7
 			switch (pid) {
0b26fc7
 			case 0: /* child */
0b26fc7
+				setgroups(0, NULL);
0b26fc7
 				setgid(0);
0b26fc7
 				setuid(0);
0b26fc7
 				execle(START_STATD, START_STATD, NULL, envp);
0b26fc7
@@ -1638,6 +1640,7 @@ int nfs_options2pmap(struct mount_options *options,
0b26fc7
 		     struct pmap *nfs_pmap, struct pmap *mnt_pmap)
0b26fc7
 {
0b26fc7
 	struct nfs_version version;
0b26fc7
+	memset(&version, 0, sizeof(version));
0b26fc7
 
0b26fc7
 	if (!nfs_nfs_program(options, &nfs_pmap->pm_prog))
0b26fc7
 		return 0;
0b26fc7
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
0b26fc7
index 387d734..c0266e5 100644
0b26fc7
--- a/utils/mount/stropts.c
0b26fc7
+++ b/utils/mount/stropts.c
0b26fc7
@@ -315,9 +315,10 @@ static int nfs_set_version(struct nfsmount_info *mi)
0b26fc7
 	if (!nfs_nfs_version(mi->options, &mi->version))
0b26fc7
 		return 0;
0b26fc7
 
0b26fc7
-	if (strncmp(mi->type, "nfs4", 4) == 0)
0b26fc7
+	if (strncmp(mi->type, "nfs4", 4) == 0) {
0b26fc7
 		mi->version.major = 4;
0b26fc7
-
0b26fc7
+		mi->version.v_mode = V_GENERAL;
0b26fc7
+	}
0b26fc7
 	/*
0b26fc7
 	 * Before 2.6.32, the kernel NFS client didn't
0b26fc7
 	 * support "-t nfs vers=4" mounts, so NFS version
0b26fc7
@@ -517,6 +518,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4)
0b26fc7
 	unsigned long protocol;
0b26fc7
 	struct pmap mnt_pmap;
0b26fc7
 
0b26fc7
+	/* initialize structs */
0b26fc7
+	memset(&nfs_pmap, 0, sizeof(struct pmap));
0b26fc7
+	memset(&mnt_pmap, 0, sizeof(struct pmap));
0b26fc7
+
0b26fc7
 	/*
0b26fc7
 	 * Version and transport negotiation is not required
0b26fc7
 	 * and does not work for RDMA mounts.
0b26fc7
@@ -834,9 +839,6 @@ check_result:
0b26fc7
 	case EINVAL:
0b26fc7
 		/* A less clear indication that our client
0b26fc7
 		 * does not support NFSv4 minor version. */
0b26fc7
-		if (mi->version.v_mode == V_GENERAL &&
0b26fc7
-			mi->version.minor == 0)
0b26fc7
-				return result;
0b26fc7
 		if (mi->version.v_mode != V_SPECIFIC) {
0b26fc7
 			if (mi->version.minor > 0) {
0b26fc7
 				mi->version.minor--;
0b26fc7
@@ -858,19 +860,28 @@ check_result:
0b26fc7
 		/* UDP-Only servers won't support v4, but maybe it
0b26fc7
 		 * just isn't ready yet.  So try v3, but double-check
0b26fc7
 		 * with rpcbind for v4. */
0b26fc7
+		if (mi->version.v_mode == V_GENERAL)
0b26fc7
+			/* Mustn't try v2,v3 */
0b26fc7
+			return result;
0b26fc7
 		result = nfs_try_mount_v3v2(mi, TRUE);
0b26fc7
 		if (result == 0 && errno == EAGAIN) {
0b26fc7
 			/* v4 server seems to be registered now. */
0b26fc7
 			result = nfs_try_mount_v4(mi);
0b26fc7
 			if (result == 0 && errno != ECONNREFUSED)
0b26fc7
 				goto check_result;
0b26fc7
-		}
0b26fc7
+		} else if (result == 0)
0b26fc7
+			/* Restore original errno with v3 failures */
0b26fc7
+			errno = ECONNREFUSED;
0b26fc7
+
0b26fc7
 		return result;
0b26fc7
 	default:
0b26fc7
 		return result;
0b26fc7
 	}
0b26fc7
 
0b26fc7
 fall_back:
0b26fc7
+	if (mi->version.v_mode == V_GENERAL)
0b26fc7
+		/* v2,3 fallback not allowed */
0b26fc7
+		return result;
0b26fc7
 	return nfs_try_mount_v3v2(mi, FALSE);
0b26fc7
 }
0b26fc7
 
0b26fc7
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
0b26fc7
index d065830..8299256 100644
0b26fc7
--- a/utils/mountd/auth.c
0b26fc7
+++ b/utils/mountd/auth.c
0b26fc7
@@ -41,6 +41,8 @@ static nfs_client my_client;
0b26fc7
 
0b26fc7
 extern int use_ipaddr;
0b26fc7
 
0b26fc7
+extern struct state_paths etab;
0b26fc7
+
0b26fc7
 void
0b26fc7
 auth_init(void)
0b26fc7
 {
0b26fc7
@@ -84,10 +86,10 @@ auth_reload()
0b26fc7
 	static unsigned int	counter;
0b26fc7
 	int			fd;
0b26fc7
 
0b26fc7
-	if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) {
0b26fc7
-		xlog(L_FATAL, "couldn't open %s", _PATH_ETAB);
0b26fc7
+	if ((fd = open(etab.statefn, O_RDONLY)) < 0) {
0b26fc7
+		xlog(L_FATAL, "couldn't open %s", etab.statefn);
0b26fc7
 	} else if (fstat(fd, &stb) < 0) {
0b26fc7
-		xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
0b26fc7
+		xlog(L_FATAL, "couldn't stat %s", etab.statefn);
0b26fc7
 		close(fd);
0b26fc7
 	} else if (last_fd != -1 && stb.st_ino == last_inode) {
0b26fc7
 		/* We opened the etab file before, and its inode
0b26fc7
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
0b26fc7
index 61699e6..829f803 100644
0b26fc7
--- a/utils/mountd/mountd.c
0b26fc7
+++ b/utils/mountd/mountd.c
0b26fc7
@@ -29,6 +29,7 @@
0b26fc7
 #include "mountd.h"
0b26fc7
 #include "rpcmisc.h"
0b26fc7
 #include "pseudoflavors.h"
0b26fc7
+#include "nfslib.h"
0b26fc7
 
0b26fc7
 extern void my_svc_run(void);
0b26fc7
 
0b26fc7
@@ -40,7 +41,8 @@ int reverse_resolve = 0;
0b26fc7
 int manage_gids;
0b26fc7
 int use_ipaddr = -1;
0b26fc7
 
0b26fc7
-char *conf_path = NFS_CONFFILE;
0b26fc7
+struct state_paths etab;
0b26fc7
+struct state_paths rmtab;
0b26fc7
 
0b26fc7
 /* PRC: a high-availability callout program can be specified with -H
0b26fc7
  * When this is done, the program will receive callouts whenever clients
0b26fc7
@@ -110,8 +112,8 @@ unregister_services (void)
0b26fc7
 static void
0b26fc7
 cleanup_lockfiles (void)
0b26fc7
 {
0b26fc7
-	unlink(_PATH_ETABLCK);
0b26fc7
-	unlink(_PATH_RMTABLCK);
0b26fc7
+	unlink(etab.lockfn);
0b26fc7
+	unlink(rmtab.lockfn);
0b26fc7
 }
0b26fc7
 
0b26fc7
 /* Wait for all worker child processes to exit and reap them */
0b26fc7
@@ -181,6 +183,8 @@ fork_workers(void)
0b26fc7
 	wait_for_workers();
0b26fc7
 	unregister_services();
0b26fc7
 	cleanup_lockfiles();
0b26fc7
+	free_state_path_names(&etab;;
0b26fc7
+	free_state_path_names(&rmtab);
0b26fc7
 	xlog(L_NOTICE, "mountd: no more workers, exiting\n");
0b26fc7
 	exit(0);
0b26fc7
 }
0b26fc7
@@ -198,6 +202,8 @@ killer (int sig)
0b26fc7
 		wait_for_workers();
0b26fc7
 	}
0b26fc7
 	cleanup_lockfiles();
0b26fc7
+	free_state_path_names(&etab;;
0b26fc7
+	free_state_path_names(&rmtab);
0b26fc7
 	xlog (L_NOTICE, "Caught signal %d, un-registering and exiting.", sig);
0b26fc7
 	exit(0);
0b26fc7
 }
0b26fc7
@@ -656,7 +662,6 @@ get_exportlist(void)
0b26fc7
 int
0b26fc7
 main(int argc, char **argv)
0b26fc7
 {
0b26fc7
-	char    *state_dir = NFS_STATEDIR;
0b26fc7
 	char	*progname;
0b26fc7
 	char	*s;
0b26fc7
 	unsigned int listeners = 0;
0b26fc7
@@ -674,7 +679,7 @@ main(int argc, char **argv)
0b26fc7
 	else
0b26fc7
 		progname = argv[0];
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
 	xlog_from_conffile("mountd");
0b26fc7
 	manage_gids = conf_get_bool("mountd", "manage-gids", manage_gids);
0b26fc7
 	descriptors = conf_get_num("mountd", "descriptors", descriptors);
0b26fc7
@@ -684,8 +689,8 @@ main(int argc, char **argv)
0b26fc7
 	ha_callout_prog = conf_get_str("mountd", "ha-callout");
0b26fc7
 
0b26fc7
 	s = conf_get_str("mountd", "state-directory-path");
0b26fc7
-	if (s)
0b26fc7
-		state_dir = s;
0b26fc7
+	if (s && !state_setup_basedir(argv[0], s))
0b26fc7
+		exit(1);
0b26fc7
 
0b26fc7
 	/* NOTE: following uses "nfsd" section of nfs.conf !!!! */
0b26fc7
 	if (conf_get_bool("nfsd", "udp", NFSCTL_UDPISSET(_rpcprotobits)))
0b26fc7
@@ -758,7 +763,8 @@ main(int argc, char **argv)
0b26fc7
 			reverse_resolve = 1;
0b26fc7
 			break;
0b26fc7
 		case 's':
0b26fc7
-			state_dir = xstrdup(optarg);
0b26fc7
+			if (!state_setup_basedir(argv[0], optarg))
0b26fc7
+				exit(1);
0b26fc7
 			break;
0b26fc7
 		case 't':
0b26fc7
 			num_threads = atoi (optarg);
0b26fc7
@@ -790,11 +796,10 @@ main(int argc, char **argv)
0b26fc7
 		fprintf(stderr, "%s: No protocol versions specified!\n", progname); 
0b26fc7
 		usage(progname, 1);
0b26fc7
 	}
0b26fc7
-	if (chdir(state_dir)) {
0b26fc7
-		fprintf(stderr, "%s: chdir(%s) failed: %s\n",
0b26fc7
-			progname, state_dir, strerror(errno));
0b26fc7
-		exit(1);
0b26fc7
-	}
0b26fc7
+	if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
0b26fc7
+		return 1;
0b26fc7
+	if (!setup_state_path_names(progname, RMTAB, RMTABTMP, RMTABLCK, &rmtab))
0b26fc7
+		return 1;
0b26fc7
 
0b26fc7
 	if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
0b26fc7
 		fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
0b26fc7
@@ -888,6 +893,8 @@ main(int argc, char **argv)
0b26fc7
 
0b26fc7
 	xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n");
0b26fc7
 	unregister_services();
0b26fc7
+	free_state_path_names(&etab;;
0b26fc7
+	free_state_path_names(&rmtab);
0b26fc7
 	exit(1);
0b26fc7
 }
0b26fc7
 
0b26fc7
diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
0b26fc7
index 9f0a51f..9978afc 100644
0b26fc7
--- a/utils/mountd/mountd.man
0b26fc7
+++ b/utils/mountd/mountd.man
0b26fc7
@@ -144,7 +144,7 @@ Instead, mount the nfsd filesystem on
0b26fc7
 .IR /proc/fs/nfsd .
0b26fc7
 .TP
0b26fc7
 .BI "\-s," "" " \-\-state\-directory\-path "  directory
0b26fc7
-Specify a directory in which to place statd state information.
0b26fc7
+Specify a directory in which to place state information (etab and rmtab).
0b26fc7
 If this option is not specified the default of
0b26fc7
 .I /var/lib/nfs
0b26fc7
 is used.
0b26fc7
diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c
0b26fc7
index 527377f..3ae0dbb 100644
0b26fc7
--- a/utils/mountd/rmtab.c
0b26fc7
+++ b/utils/mountd/rmtab.c
0b26fc7
@@ -28,6 +28,8 @@
0b26fc7
 
0b26fc7
 extern int reverse_resolve;
0b26fc7
 
0b26fc7
+extern struct state_paths rmtab;
0b26fc7
+
0b26fc7
 /* If new path is a link do not destroy it but place the
0b26fc7
  * file where the link points.
0b26fc7
  */
0b26fc7
@@ -59,7 +61,7 @@ mountlist_add(char *host, const char *path)
0b26fc7
 	int		lockid;
0b26fc7
 	long		pos;
0b26fc7
 
0b26fc7
-	if ((lockid = xflock(_PATH_RMTABLCK, "a")) < 0)
0b26fc7
+	if ((lockid = xflock(rmtab.lockfn, "a")) < 0)
0b26fc7
 		return;
0b26fc7
 	setrmtabent("r+");
0b26fc7
 	while ((rep = getrmtabent(1, &pos)) != NULL) {
0b26fc7
@@ -99,13 +101,13 @@ mountlist_del(char *hname, const char *path)
0b26fc7
 	int		lockid;
0b26fc7
 	int		match;
0b26fc7
 
0b26fc7
-	if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
0b26fc7
+	if ((lockid = xflock(rmtab.lockfn, "w")) < 0)
0b26fc7
 		return;
0b26fc7
 	if (!setrmtabent("r")) {
0b26fc7
 		xfunlock(lockid);
0b26fc7
 		return;
0b26fc7
 	}
0b26fc7
-	if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) {
0b26fc7
+	if (!(fp = fsetrmtabent(rmtab.tmpfn, "w"))) {
0b26fc7
 		endrmtabent();
0b26fc7
 		xfunlock(lockid);
0b26fc7
 		return;
0b26fc7
@@ -121,9 +123,9 @@ mountlist_del(char *hname, const char *path)
0b26fc7
 		if (!match || rep->r_count)
0b26fc7
 			fputrmtabent(fp, rep, NULL);
0b26fc7
 	}
0b26fc7
-	if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
0b26fc7
+	if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) {
0b26fc7
 		xlog(L_ERROR, "couldn't rename %s to %s",
0b26fc7
-				_PATH_RMTABTMP, _PATH_RMTAB);
0b26fc7
+				rmtab.tmpfn, rmtab.statefn);
0b26fc7
 	}
0b26fc7
 	endrmtabent();	/* close & unlink */
0b26fc7
 	fendrmtabent(fp);
0b26fc7
@@ -138,7 +140,7 @@ mountlist_del_all(const struct sockaddr *sap)
0b26fc7
 	FILE		*fp;
0b26fc7
 	int		lockid;
0b26fc7
 
0b26fc7
-	if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
0b26fc7
+	if ((lockid = xflock(rmtab.lockfn, "w")) < 0)
0b26fc7
 		return;
0b26fc7
 	hostname = host_canonname(sap);
0b26fc7
 	if (hostname == NULL) {
0b26fc7
@@ -151,7 +153,7 @@ mountlist_del_all(const struct sockaddr *sap)
0b26fc7
 	if (!setrmtabent("r"))
0b26fc7
 		goto out_free;
0b26fc7
 
0b26fc7
-	if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w")))
0b26fc7
+	if (!(fp = fsetrmtabent(rmtab.tmpfn, "w")))
0b26fc7
 		goto out_close;
0b26fc7
 
0b26fc7
 	while ((rep = getrmtabent(1, NULL)) != NULL) {
0b26fc7
@@ -160,9 +162,9 @@ mountlist_del_all(const struct sockaddr *sap)
0b26fc7
 			continue;
0b26fc7
 		fputrmtabent(fp, rep, NULL);
0b26fc7
 	}
0b26fc7
-	if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
0b26fc7
+	if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) {
0b26fc7
 		xlog(L_ERROR, "couldn't rename %s to %s",
0b26fc7
-				_PATH_RMTABTMP, _PATH_RMTAB);
0b26fc7
+				rmtab.tmpfn, rmtab.statefn);
0b26fc7
 	}
0b26fc7
 	fendrmtabent(fp);
0b26fc7
 out_close:
0b26fc7
@@ -195,11 +197,11 @@ mountlist_list(void)
0b26fc7
 	struct stat		stb;
0b26fc7
 	int			lockid;
0b26fc7
 
0b26fc7
-	if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
0b26fc7
+	if ((lockid = xflock(rmtab.lockfn, "r")) < 0)
0b26fc7
 		return NULL;
0b26fc7
-	if (stat(_PATH_RMTAB, &stb) < 0) {
0b26fc7
+	if (stat(rmtab.statefn, &stb) < 0) {
0b26fc7
 		xlog(L_ERROR, "can't stat %s: %s",
0b26fc7
-				_PATH_RMTAB, strerror(errno));
0b26fc7
+				rmtab.statefn, strerror(errno));
0b26fc7
 		xfunlock(lockid);
0b26fc7
 		return NULL;
0b26fc7
 	}
0b26fc7
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
0b26fc7
index 20f4b79..111058f 100644
0b26fc7
--- a/utils/nfsd/nfsd.c
0b26fc7
+++ b/utils/nfsd/nfsd.c
0b26fc7
@@ -34,8 +34,6 @@
0b26fc7
 #define NFSD_NPROC 8
0b26fc7
 #endif
0b26fc7
 
0b26fc7
-char *conf_path = NFS_CONFFILE;
0b26fc7
-
0b26fc7
 static void	usage(const char *);
0b26fc7
 
0b26fc7
 static struct option longopts[] =
0b26fc7
@@ -44,7 +42,9 @@ static struct option longopts[] =
0b26fc7
 	{ "help", 0, 0, 'h' },
0b26fc7
 	{ "no-nfs-version", 1, 0, 'N' },
0b26fc7
 	{ "nfs-version", 1, 0, 'V' },
0b26fc7
+	{ "tcp", 0, 0, 't' },
0b26fc7
 	{ "no-tcp", 0, 0, 'T' },
0b26fc7
+	{ "udp", 0, 0, 'u' },
0b26fc7
 	{ "no-udp", 0, 0, 'U' },
0b26fc7
 	{ "port", 1, 0, 'P' },
0b26fc7
 	{ "port", 1, 0, 'p' },
0b26fc7
@@ -67,8 +67,9 @@ main(int argc, char **argv)
0b26fc7
 	int	socket_up = 0;
0b26fc7
 	unsigned int minorvers = 0;
0b26fc7
 	unsigned int minorversset = 0;
0b26fc7
+	unsigned int minormask = 0;
0b26fc7
 	unsigned int versbits = NFSCTL_VERDEFAULT;
0b26fc7
-	unsigned int protobits = NFSCTL_ALLBITS;
0b26fc7
+	unsigned int protobits = NFSCTL_PROTODEFAULT;
0b26fc7
 	int grace = -1;
0b26fc7
 	int lease = -1;
0b26fc7
 
0b26fc7
@@ -79,7 +80,7 @@ main(int argc, char **argv)
0b26fc7
 	xlog_syslog(0);
0b26fc7
 	xlog_stderr(1);
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE); 
0b26fc7
 	xlog_from_conffile("nfsd");
0b26fc7
 	count = conf_get_num("nfsd", "threads", count);
0b26fc7
 	grace = conf_get_num("nfsd", "grace-time", grace);
0b26fc7
@@ -104,10 +105,16 @@ main(int argc, char **argv)
0b26fc7
 		else
0b26fc7
 			NFSCTL_VERUNSET(versbits, i);
0b26fc7
 	}
0b26fc7
+
0b26fc7
+	nfssvc_get_minormask(&minormask);
0b26fc7
 	/* We assume the kernel will default all minor versions to 'on',
0b26fc7
 	 * and allow the config file to disable some.
0b26fc7
 	 */
0b26fc7
-	for (i = NFS4_MINMINOR; i <= NFS4_MAXMINOR; i++) {
0b26fc7
+	if (NFSCTL_VERISSET(versbits, 4)) {
0b26fc7
+		NFSCTL_MINORSET(minorversset, 0);
0b26fc7
+		NFSCTL_MINORSET(minorvers, 0);
0b26fc7
+	}
0b26fc7
+	for (i = 1; i <= NFS4_MAXMINOR; i++) {
0b26fc7
 		char tag[20];
0b26fc7
 		sprintf(tag, "vers4.%d", i);
0b26fc7
 		/* The default for minor version support is to let the
0b26fc7
@@ -119,12 +126,12 @@ main(int argc, char **argv)
0b26fc7
 		 * (i.e. don't set the bit in minorversset).
0b26fc7
 		 */
0b26fc7
 		if (!conf_get_bool("nfsd", tag, 1)) {
0b26fc7
-			NFSCTL_VERSET(minorversset, i);
0b26fc7
-			NFSCTL_VERUNSET(minorvers, i);
0b26fc7
+			NFSCTL_MINORSET(minorversset, i);
0b26fc7
+			NFSCTL_MINORUNSET(minorvers, i);
0b26fc7
 		}
0b26fc7
 		if (conf_get_bool("nfsd", tag, 0)) {
0b26fc7
-			NFSCTL_VERSET(minorversset, i);
0b26fc7
-			NFSCTL_VERSET(minorvers, i);
0b26fc7
+			NFSCTL_MINORSET(minorversset, i);
0b26fc7
+			NFSCTL_MINORSET(minorvers, i);
0b26fc7
 		}
0b26fc7
 	}
0b26fc7
 
0b26fc7
@@ -138,7 +145,7 @@ main(int argc, char **argv)
0b26fc7
 		}
0b26fc7
 	}
0b26fc7
 
0b26fc7
-	while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTUrG:L:", longopts, NULL)) != EOF) {
0b26fc7
+	while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTitUrG:L:", longopts, NULL)) != EOF) {
0b26fc7
 		switch(c) {
0b26fc7
 		case 'd':
0b26fc7
 			xlog_config(D_ALL, 1);
0b26fc7
@@ -179,13 +186,17 @@ main(int argc, char **argv)
0b26fc7
 			case 4:
0b26fc7
 				if (*p == '.') {
0b26fc7
 					int i = atoi(p+1);
0b26fc7
-					if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) {
0b26fc7
+					if (i < 0 || i > NFS4_MAXMINOR) {
0b26fc7
 						fprintf(stderr, "%s: unsupported minor version\n", optarg);
0b26fc7
 						exit(1);
0b26fc7
 					}
0b26fc7
-					NFSCTL_VERSET(minorversset, i);
0b26fc7
-					NFSCTL_VERUNSET(minorvers, i);
0b26fc7
-					break;
0b26fc7
+					NFSCTL_MINORSET(minorversset, i);
0b26fc7
+					NFSCTL_MINORUNSET(minorvers, i);
0b26fc7
+					if (minorvers != 0)
0b26fc7
+						break;
0b26fc7
+				} else {
0b26fc7
+					minorvers = 0;
0b26fc7
+					minorversset = minormask;
0b26fc7
 				}
0b26fc7
 			case 3:
0b26fc7
 			case 2:
0b26fc7
@@ -201,14 +212,14 @@ main(int argc, char **argv)
0b26fc7
 			case 4:
0b26fc7
 				if (*p == '.') {
0b26fc7
 					int i = atoi(p+1);
0b26fc7
-					if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) {
0b26fc7
+					if (i < 0 || i > NFS4_MAXMINOR) {
0b26fc7
 						fprintf(stderr, "%s: unsupported minor version\n", optarg);
0b26fc7
 						exit(1);
0b26fc7
 					}
0b26fc7
-					NFSCTL_VERSET(minorversset, i);
0b26fc7
-					NFSCTL_VERSET(minorvers, i);
0b26fc7
-					break;
0b26fc7
-				}
0b26fc7
+					NFSCTL_MINORSET(minorversset, i);
0b26fc7
+					NFSCTL_MINORSET(minorvers, i);
0b26fc7
+				} else
0b26fc7
+					minorvers = minorversset = minormask;
0b26fc7
 			case 3:
0b26fc7
 			case 2:
0b26fc7
 				NFSCTL_VERSET(versbits, c);
0b26fc7
@@ -222,9 +233,15 @@ main(int argc, char **argv)
0b26fc7
 			xlog_syslog(1);
0b26fc7
 			xlog_stderr(0);
0b26fc7
 			break;
0b26fc7
+		case 't':
0b26fc7
+			NFSCTL_TCPSET(protobits);
0b26fc7
+			break;
0b26fc7
 		case 'T':
0b26fc7
 			NFSCTL_TCPUNSET(protobits);
0b26fc7
 			break;
0b26fc7
+		case 'u':
0b26fc7
+			NFSCTL_UDPSET(protobits);
0b26fc7
+			break;
0b26fc7
 		case 'U':
0b26fc7
 			NFSCTL_UDPUNSET(protobits);
0b26fc7
 			break;
0b26fc7
@@ -372,9 +389,9 @@ usage(const char *prog)
0b26fc7
 {
0b26fc7
 	fprintf(stderr, "Usage:\n"
0b26fc7
 		"%s [-d|--debug] [-H hostname] [-p|-P|--port port]\n"
0b26fc7
-		"     [-N|--no-nfs-version version] [-V|--nfs-version version]\n"
0b26fc7
-		"     [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] [-r|--rdma=]\n"
0b26fc7
-		"     [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n",
0b26fc7
+		"   [-N|--no-nfs-version version] [-V|--nfs-version version]\n"
0b26fc7
+		"   [-s|--syslog] [-t|--tcp] [-T|--no-tcp] [-u|--udp] [-U|--no-udp]\n"
0b26fc7
+		"   [-r|--rdma=] [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n",
0b26fc7
 		prog);
0b26fc7
 	exit(2);
0b26fc7
 }
0b26fc7
diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man
0b26fc7
index 8901fb6..d83ef86 100644
0b26fc7
--- a/utils/nfsd/nfsd.man
0b26fc7
+++ b/utils/nfsd/nfsd.man
0b26fc7
@@ -57,7 +57,7 @@ This option can be used to request that
0b26fc7
 .B rpc.nfsd
0b26fc7
 does not offer certain versions of NFS. The current version of
0b26fc7
 .B rpc.nfsd
0b26fc7
-can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2.
0b26fc7
+can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2.
0b26fc7
 .TP
0b26fc7
 .B \-s " or " \-\-syslog
0b26fc7
 By default,
0b26fc7
@@ -67,22 +67,24 @@ logs error messages (and debug messages, if enabled) to stderr. This option make
0b26fc7
 log these messages to syslog instead. Note that errors encountered during
0b26fc7
 option processing will still be logged to stderr regardless of this option.
0b26fc7
 .TP
0b26fc7
+.B \-t " or " \-\-tcp
0b26fc7
+Instruct the kernel nfs server to open and listen on a TCP socket. This is the default.
0b26fc7
+.TP
0b26fc7
 .B \-T " or " \-\-no-tcp
0b26fc7
-Disable 
0b26fc7
-.B rpc.nfsd 
0b26fc7
-from accepting TCP connections from clients.
0b26fc7
+Instruct the kernel nfs server not to open and listen on a TCP socket.
0b26fc7
+.TP
0b26fc7
+.B \-u " or " \-\-udp
0b26fc7
+Instruct the kernel nfs server to open and listen on a UDP socket.
0b26fc7
 .TP
0b26fc7
 .B \-U " or " \-\-no-udp
0b26fc7
-Disable
0b26fc7
-.B rpc.nfsd
0b26fc7
-from accepting UDP connections from clients.
0b26fc7
+Instruct the kernel nfs server not to open and listen on a UDP socket. This is the default.
0b26fc7
 .TP
0b26fc7
 .B \-V " or " \-\-nfs-version vers
0b26fc7
 This option can be used to request that 
0b26fc7
 .B rpc.nfsd
0b26fc7
 offer certain versions of NFS. The current version of
0b26fc7
 .B rpc.nfsd
0b26fc7
-can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2.
0b26fc7
+can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2.
0b26fc7
 .TP
0b26fc7
 .B \-L " or " \-\-lease-time seconds
0b26fc7
 Set the lease-time used for NFSv4.  This corresponds to how often
0b26fc7
diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
0b26fc7
index 07f6ff1..e8609c1 100644
0b26fc7
--- a/utils/nfsd/nfssvc.c
0b26fc7
+++ b/utils/nfsd/nfssvc.c
0b26fc7
@@ -330,36 +330,78 @@ nfssvc_set_time(const char *type, const int seconds)
0b26fc7
 }
0b26fc7
 
0b26fc7
 void
0b26fc7
+nfssvc_get_minormask(unsigned int *mask)
0b26fc7
+{
0b26fc7
+	int fd;
0b26fc7
+	char *ptr = buf;
0b26fc7
+	ssize_t size;
0b26fc7
+
0b26fc7
+	fd = open(NFSD_VERS_FILE, O_RDONLY);
0b26fc7
+	if (fd < 0)
0b26fc7
+		return;
0b26fc7
+
0b26fc7
+	size = read(fd, buf, sizeof(buf));
0b26fc7
+	if (size < 0) {
0b26fc7
+		xlog(L_ERROR, "Getting versions failed: errno %d (%m)", errno);
0b26fc7
+		goto out;
0b26fc7
+	}
0b26fc7
+	ptr[size] = '\0';
0b26fc7
+	for (;;) {
0b26fc7
+		unsigned vers, minor = 0;
0b26fc7
+		char *token = strtok(ptr, " ");
0b26fc7
+
0b26fc7
+		if (!token)
0b26fc7
+			break;
0b26fc7
+		ptr = NULL;
0b26fc7
+		if (*token != '+' && *token != '-')
0b26fc7
+			continue;
0b26fc7
+		if (sscanf(++token, "%u.%u", &vers, &minor) > 0 &&
0b26fc7
+		    vers == 4 && minor <= NFS4_MAXMINOR)
0b26fc7
+			NFSCTL_MINORSET(*mask, minor);
0b26fc7
+	}
0b26fc7
+out:
0b26fc7
+	close(fd);
0b26fc7
+	return;
0b26fc7
+}
0b26fc7
+
0b26fc7
+static int
0b26fc7
+nfssvc_print_vers(char *ptr, unsigned size, unsigned vers, unsigned minorvers,
0b26fc7
+		int isset)
0b26fc7
+{
0b26fc7
+	char sign = isset ? '+' : '-';
0b26fc7
+	if (minorvers == 0)
0b26fc7
+		return snprintf(ptr, size, "%c%u ", sign, vers);
0b26fc7
+	return snprintf(ptr, size, "%c%u.%u ", sign, vers, minorvers);
0b26fc7
+}
0b26fc7
+
0b26fc7
+void
0b26fc7
 nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers, unsigned int minorversset)
0b26fc7
 {
0b26fc7
 	int fd, n, off;
0b26fc7
-	char *ptr;
0b26fc7
 
0b26fc7
-	ptr = buf;
0b26fc7
 	off = 0;
0b26fc7
 	fd = open(NFSD_VERS_FILE, O_WRONLY);
0b26fc7
 	if (fd < 0)
0b26fc7
 		return;
0b26fc7
 
0b26fc7
-	for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) {
0b26fc7
-		if (NFSCTL_VERISSET(minorversset, n)) {
0b26fc7
-			if (NFSCTL_VERISSET(minorvers, n))
0b26fc7
-				off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n);
0b26fc7
-			else
0b26fc7
-				off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n);
0b26fc7
-		}
0b26fc7
-	}
0b26fc7
-	for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
0b26fc7
-		if (NFSCTL_VERISSET(ctlbits, n))
0b26fc7
-		    off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
0b26fc7
-		else
0b26fc7
-		    off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
0b26fc7
+	for (n = NFSD_MINVERS; n <= ((NFSD_MAXVERS < 3) ? NFSD_MAXVERS : 3); n++)
0b26fc7
+		off += nfssvc_print_vers(&buf[off], sizeof(buf) - off,
0b26fc7
+				n, 0, NFSCTL_VERISSET(ctlbits, n));
0b26fc7
+
0b26fc7
+	for (n = 0; n <= NFS4_MAXMINOR; n++) {
0b26fc7
+		if (!NFSCTL_MINORISSET(minorversset, n))
0b26fc7
+			continue;
0b26fc7
+		off += nfssvc_print_vers(&buf[off], sizeof(buf) - off,
0b26fc7
+				4, n, NFSCTL_MINORISSET(minorvers, n));
0b26fc7
 	}
0b26fc7
+	if (!off--)
0b26fc7
+		goto out;
0b26fc7
+	buf[off] = '\0';
0b26fc7
 	xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
0b26fc7
-	snprintf(ptr+off, sizeof(buf) - off, "\n");
0b26fc7
+	snprintf(&buf[off], sizeof(buf) - off, "\n");
0b26fc7
 	if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
0b26fc7
 		xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
0b26fc7
-
0b26fc7
+out:
0b26fc7
 	close(fd);
0b26fc7
 
0b26fc7
 	return;
0b26fc7
diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h
0b26fc7
index cd5a7e8..39ebf37 100644
0b26fc7
--- a/utils/nfsd/nfssvc.h
0b26fc7
+++ b/utils/nfsd/nfssvc.h
0b26fc7
@@ -28,3 +28,4 @@ void	nfssvc_set_time(const char *type, const int seconds);
0b26fc7
 int	nfssvc_set_rdmaport(const char *port);
0b26fc7
 void	nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers4, unsigned int minorvers4set);
0b26fc7
 int	nfssvc_threads(int nrservs);
0b26fc7
+void	nfssvc_get_minormask(unsigned int *mask);
0b26fc7
diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c
0b26fc7
index 7af9efb..124c923 100644
0b26fc7
--- a/utils/nfsdcltrack/nfsdcltrack.c
0b26fc7
+++ b/utils/nfsdcltrack/nfsdcltrack.c
0b26fc7
@@ -56,8 +56,6 @@
0b26fc7
 /* defined by RFC 3530 */
0b26fc7
 #define NFS4_OPAQUE_LIMIT	1024
0b26fc7
 
0b26fc7
-char *conf_path = NFS_CONFFILE;
0b26fc7
-
0b26fc7
 /* private data structures */
0b26fc7
 struct cltrack_cmd {
0b26fc7
 	char *name;
0b26fc7
@@ -566,7 +564,7 @@ main(int argc, char **argv)
0b26fc7
 	xlog_syslog(1);
0b26fc7
 	xlog_stderr(0);
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE); 
0b26fc7
 	xlog_from_conffile("nfsdcltrack");
0b26fc7
 	val = conf_get_str("nfsdcltrack", "storagedir");
0b26fc7
 	if (val)
0b26fc7
diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c
0b26fc7
index 54cd748..1552eba 100644
0b26fc7
--- a/utils/nfsdcltrack/sqlite.c
0b26fc7
+++ b/utils/nfsdcltrack/sqlite.c
0b26fc7
@@ -101,7 +101,7 @@ sqlite_query_schema_version(void)
0b26fc7
 		"SELECT value FROM parameters WHERE key == \"version\";",
0b26fc7
 		 -1, &stmt, NULL);
0b26fc7
 	if (ret != SQLITE_OK) {
0b26fc7
-		xlog(L_ERROR, "Unable to prepare select statement: %s",
0b26fc7
+		xlog(D_GENERAL, "Unable to prepare select statement: %s",
0b26fc7
 			sqlite3_errmsg(dbh));
0b26fc7
 		ret = 0;
0b26fc7
 		goto out;
0b26fc7
@@ -110,7 +110,7 @@ sqlite_query_schema_version(void)
0b26fc7
 	/* query schema version */
0b26fc7
 	ret = sqlite3_step(stmt);
0b26fc7
 	if (ret != SQLITE_ROW) {
0b26fc7
-		xlog(L_ERROR, "Select statement execution failed: %s",
0b26fc7
+		xlog(D_GENERAL, "Select statement execution failed: %s",
0b26fc7
 				sqlite3_errmsg(dbh));
0b26fc7
 		ret = 0;
0b26fc7
 		goto out;
0b26fc7
diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am
0b26fc7
index 152b680..ea32075 100644
0b26fc7
--- a/utils/statd/Makefile.am
0b26fc7
+++ b/utils/statd/Makefile.am
0b26fc7
@@ -18,6 +18,7 @@ statd_LDADD = ../../support/nsm/libnsm.a \
0b26fc7
 	      $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC)
0b26fc7
 sm_notify_LDADD = ../../support/nsm/libnsm.a \
0b26fc7
 		  ../../support/nfs/libnfs.a \
0b26fc7
+	          ../../support/misc/libmisc.a \
0b26fc7
 		  $(LIBNSL) $(LIBCAP) $(LIBTIRPC)
0b26fc7
 
0b26fc7
 EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c
0b26fc7
diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c
0b26fc7
index 623213e..d216ddb 100644
0b26fc7
--- a/utils/statd/sm-notify.c
0b26fc7
+++ b/utils/statd/sm-notify.c
0b26fc7
@@ -45,6 +45,8 @@
0b26fc7
 
0b26fc7
 #define NLM_END_GRACE_FILE	"/proc/fs/lockd/nlm_end_grace"
0b26fc7
 
0b26fc7
+int lift_grace = 1;
0b26fc7
+
0b26fc7
 struct nsm_host {
0b26fc7
 	struct nsm_host *	next;
0b26fc7
 	char *			name;
0b26fc7
@@ -67,7 +69,6 @@ static _Bool		opt_update_state = true;
0b26fc7
 static unsigned int	opt_max_retry = 15 * 60;
0b26fc7
 static char *		opt_srcaddr = NULL;
0b26fc7
 static char *		opt_srcport = NULL;
0b26fc7
-char *			conf_path = NFS_CONFFILE;
0b26fc7
 
0b26fc7
 static void		notify(const int sock);
0b26fc7
 static int		notify_host(int, struct nsm_host *);
0b26fc7
@@ -489,11 +490,12 @@ main(int argc, char **argv)
0b26fc7
 	else
0b26fc7
 		progname = argv[0];
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
 	xlog_from_conffile("sm-notify");
0b26fc7
 	opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60;
0b26fc7
 	opt_srcport = conf_get_str("sm-notify", "outgoing-port");
0b26fc7
 	opt_srcaddr = conf_get_str("sm-notify", "outgoing-addr");
0b26fc7
+	lift_grace = conf_get_bool("sm-notify", "lift-grace", lift_grace);
0b26fc7
 	s = conf_get_str("statd", "state-directory-path");
0b26fc7
 	if (s && !nsm_setup_pathnames(argv[0], s))
0b26fc7
 		exit(1);
0b26fc7
@@ -570,7 +572,8 @@ usage:		fprintf(stderr,
0b26fc7
 	(void)nsm_retire_monitored_hosts();
0b26fc7
 	if (nsm_load_notify_list(smn_get_host) == 0) {
0b26fc7
 		xlog(D_GENERAL, "No hosts to notify; exiting");
0b26fc7
-		nsm_lift_grace_period();
0b26fc7
+		if (lift_grace)
0b26fc7
+			nsm_lift_grace_period();
0b26fc7
 		return 0;
0b26fc7
 	}
0b26fc7
 
0b26fc7
diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man
0b26fc7
index bb7f6e0..cfe1e4b 100644
0b26fc7
--- a/utils/statd/sm-notify.man
0b26fc7
+++ b/utils/statd/sm-notify.man
0b26fc7
@@ -241,6 +241,24 @@ These have the same effect as the command line options
0b26fc7
 .B v
0b26fc7
 respectively.
0b26fc7
 
0b26fc7
+An additional value recognized in the
0b26fc7
+.B [sm-notify]
0b26fc7
+section is
0b26fc7
+.BR lift-grace .
0b26fc7
+By default,
0b26fc7
+.B sm-notify
0b26fc7
+will lift lockd's grace period early if it has no hosts to notify.
0b26fc7
+Some high availability configurations will run one
0b26fc7
+.B sm-notify
0b26fc7
+per floating IP address.  In these configurations, lifting the
0b26fc7
+grace period early may prevent clients from reclaiming locks.
0b26fc7
+.RB "Setting " lift-grace " to " n
0b26fc7
+will prevent
0b26fc7
+.B sm-notify
0b26fc7
+from ending the grace period early.
0b26fc7
+.B lift-grace
0b26fc7
+has no corresponding command line option.
0b26fc7
+
0b26fc7
 The value recognized in the
0b26fc7
 .B [statd]
0b26fc7
 section is
0b26fc7
diff --git a/utils/statd/statd.c b/utils/statd/statd.c
0b26fc7
index d333b29..1443715 100644
0b26fc7
--- a/utils/statd/statd.c
0b26fc7
+++ b/utils/statd/statd.c
0b26fc7
@@ -37,7 +37,6 @@
0b26fc7
 #include <sys/socket.h>
0b26fc7
 
0b26fc7
 int	run_mode = 0;		/* foreground logging mode */
0b26fc7
-char	*conf_path = NFS_CONFFILE;
0b26fc7
 
0b26fc7
 /* LH - I had these local to main, but it seemed silly to have 
0b26fc7
  * two copies of each - one in main(), one static in log.c... 
0b26fc7
@@ -274,7 +273,7 @@ int main (int argc, char **argv)
0b26fc7
 	/* Set hostname */
0b26fc7
 	MY_NAME = NULL;
0b26fc7
 
0b26fc7
-	conf_init();
0b26fc7
+	conf_init(NFS_CONFFILE);
0b26fc7
 	xlog_from_conffile("statd");
0b26fc7
 	out_port = conf_get_num("statd", "outgoing-port", out_port);
0b26fc7
 	port = conf_get_num("statd", "port", port);