From b4bc034399ab32972091302fdecb504279689e74 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Thu, 27 Jul 2017 13:45:37 -0400 Subject: [PATCH] Updated to the latest RC releease: nfs-utils-2-1-2-rc5 Signed-off-by: Steve Dickson --- nfs-utils-2.1.2-rc2.patch | 2338 ----------------- ...1.2-rc3.patch => nfs-utils-2.1.2-rc5.patch | 981 ++++++- nfs-utils.spec | 9 +- 3 files changed, 942 insertions(+), 2386 deletions(-) delete mode 100644 nfs-utils-2.1.2-rc2.patch rename nfs-utils-2.1.2-rc3.patch => nfs-utils-2.1.2-rc5.patch (73%) diff --git a/nfs-utils-2.1.2-rc2.patch b/nfs-utils-2.1.2-rc2.patch deleted file mode 100644 index abff896..0000000 --- a/nfs-utils-2.1.2-rc2.patch +++ /dev/null @@ -1,2338 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 126d12c..941aca0 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -70,6 +70,7 @@ tests/nsm_client/nlm_sm_inter_svc.c - tests/nsm_client/nlm_sm_inter_xdr.c - utils/nfsidmap/nfsidmap - systemd/nfs-server-generator -+systemd/rpc-pipefs-generator - systemd/nfs-config.service - systemd/rpc-gssd.service - # cscope database files -diff --git a/nfs.conf b/nfs.conf -index 81ece06..0d0ec9b 100644 ---- a/nfs.conf -+++ b/nfs.conf -@@ -1,7 +1,10 @@ - # --# This is a general conifguration for the -+# This is a general configuration for the - # NFS daemons and tools - # -+#[general] -+# pipefs-directory=/var/lib/nfs/rpc_pipefs -+# - #[exportfs] - # debug=0 - # -@@ -12,7 +15,6 @@ - # limit-to-legacy-enctypes=0 - # context-timeout=0 - # rpc-timeout=5 --# pipefs-directory=/var/lib/nfs/rpc_pipefs - # keytab-file=/etc/krb5.keytab - # cred-cache-directory= - # preferred-realm= -@@ -42,7 +44,7 @@ - # port=0 - # grace-time=90 - # lease-time=90 --# udp=y -+# udp=n - # tcp=y - # vers2=n - # vers3=y -@@ -65,6 +67,7 @@ - # retry-time=900 - # outgoing-port= - # outgoing-addr= -+# lift-grace=y - # - #[svcgssd] - # principal= -diff --git a/support/export/xtab.c b/support/export/xtab.c -index 22cf539..d42eeef 100644 ---- a/support/export/xtab.c -+++ b/support/export/xtab.c -@@ -14,12 +14,20 @@ - #include - #include - #include -+#include -+#include -+#include -+#include - - #include "nfslib.h" - #include "exportfs.h" - #include "xio.h" - #include "xlog.h" - #include "v4root.h" -+#include "misc.h" -+ -+static char state_base_dirname[PATH_MAX] = NFS_STATEDIR; -+extern struct state_paths etab; - - int v4root_needed; - static void cond_rename(char *newfile, char *oldfile); -@@ -65,7 +73,7 @@ xtab_read(char *xtab, char *lockfn, int is_export) - int - xtab_export_read(void) - { -- return xtab_read(_PATH_ETAB, _PATH_ETABLCK, 1); -+ return xtab_read(etab.statefn, etab.lockfn, 1); - } - - /* -@@ -112,7 +120,7 @@ xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export) - int - xtab_export_write() - { -- return xtab_write(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1); -+ return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1); - } - - /* -@@ -158,3 +166,74 @@ static void cond_rename(char *newfile, char *oldfile) - rename(newfile, oldfile); - return; - } -+ -+/* -+ * Returns a dynamically allocated, '\0'-terminated buffer -+ * containing an appropriate pathname, or NULL if an error -+ * occurs. Caller must free the returned result with free(3). -+ */ -+static char * -+state_make_pathname(const char *tabname) -+{ -+ return generic_make_pathname(state_base_dirname, tabname); -+} -+ -+/** -+ * state_setup_basedir - set up basedir -+ * @progname: C string containing name of program, for error messages -+ * @parentdir: C string containing pathname to on-disk state, or NULL -+ * -+ * This runs before logging is set up, so error messages are directed -+ * to stderr. -+ * -+ * Returns true and sets up our basedir, if @parentdir was valid -+ * and usable; otherwise false is returned. -+ */ -+_Bool -+state_setup_basedir(const char *progname, const char *parentdir) -+{ -+ return generic_setup_basedir(progname, parentdir, state_base_dirname, -+ PATH_MAX); -+} -+ -+int -+setup_state_path_names(const char *progname, const char *statefn, -+ const char *tmpfn, const char *lockfn, -+ struct state_paths *paths) -+{ -+ paths->statefn = state_make_pathname(statefn); -+ if (!paths->statefn) { -+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n", -+ progname, statefn); -+ goto out_err; -+ } -+ paths->tmpfn = state_make_pathname(tmpfn); -+ if (!paths->tmpfn) { -+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n", -+ progname, tmpfn); -+ goto out_free_statefn; -+ } -+ paths->lockfn = state_make_pathname(lockfn); -+ if (!paths->lockfn) { -+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n", -+ progname, lockfn); -+ goto out_free_tmpfn; -+ } -+ return 1; -+ -+out_free_tmpfn: -+ free(paths->tmpfn); -+out_free_statefn: -+ free(paths->statefn); -+out_err: -+ return 0; -+ -+} -+ -+void -+free_state_path_names(struct state_paths *paths) -+{ -+ free(paths->statefn); -+ free(paths->tmpfn); -+ free(paths->lockfn); -+} -diff --git a/support/include/misc.h b/support/include/misc.h -index eedc1fe..06e2a0c 100644 ---- a/support/include/misc.h -+++ b/support/include/misc.h -@@ -15,6 +15,9 @@ - int randomkey(unsigned char *keyout, int len); - int weakrandomkey(unsigned char *keyout, int len); - -+char *generic_make_pathname(const char *, const char *); -+_Bool generic_setup_basedir(const char *, const char *, char *, const size_t); -+ - extern int is_mountpoint(char *path); - - /* size of the file pointer buffers for rpc procfs files */ -diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h -index 15ecc6b..7933ff5 100644 ---- a/support/include/nfs/nfs.h -+++ b/support/include/nfs/nfs.h -@@ -16,8 +16,8 @@ - #define NFSD_MINVERS 2 - #define NFSD_MAXVERS 4 - --#define NFS4_MINMINOR 1 --#define NFS4_MAXMINOR WORD_BIT -+#define NFS4_MINMINOR 0 -+#define NFS4_MAXMINOR (WORD_BIT-1) - - struct nfs_fh_len { - int fh_size; -@@ -27,21 +27,24 @@ struct nfs_fh_len { - - #define NFSCTL_UDPBIT (1 << (17 - 1)) - #define NFSCTL_TCPBIT (1 << (18 - 1)) -+#define NFSCTL_PROTODEFAULT (NFSCTL_TCPBIT) - - #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) -+#define NFSCTL_MINORUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) - #define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_UDPBIT) - #define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_TCPBIT) - - #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) -+#define NFSCTL_MINORISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) - #define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) - #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) - - #define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ - #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) -+#define NFSCTL_MINORSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) - #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) - #define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) - - #define NFSCTL_ANYPROTO(_cltbits) ((_cltbits) & (NFSCTL_UDPBIT | NFSCTL_TCPBIT)) --#define NFSCTL_ALLBITS (~0) - - #endif /* _NFS_NFS_H */ -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index 1498977..ab8b2bf 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -35,29 +35,24 @@ - #ifndef _PATH_IDMAPDCONF - #define _PATH_IDMAPDCONF "/etc/idmapd.conf" - #endif --#ifndef _PATH_ETAB --#define _PATH_ETAB NFS_STATEDIR "/etab" --#endif --#ifndef _PATH_ETABTMP --#define _PATH_ETABTMP NFS_STATEDIR "/etab.tmp" --#endif --#ifndef _PATH_ETABLCK --#define _PATH_ETABLCK NFS_STATEDIR "/.etab.lock" --#endif --#ifndef _PATH_RMTAB --#define _PATH_RMTAB NFS_STATEDIR "/rmtab" --#endif --#ifndef _PATH_RMTABTMP --#define _PATH_RMTABTMP _PATH_RMTAB ".tmp" --#endif --#ifndef _PATH_RMTABLCK --#define _PATH_RMTABLCK NFS_STATEDIR "/.rmtab.lock" --#endif - #ifndef _PATH_PROC_EXPORTS - #define _PATH_PROC_EXPORTS "/proc/fs/nfs/exports" - #define _PATH_PROC_EXPORTS_ALT "/proc/fs/nfsd/exports" - #endif - -+#define ETAB "etab" -+#define ETABTMP "etab.tmp" -+#define ETABLCK ".etab.lock" -+#define RMTAB "rmtab" -+#define RMTABTMP "rmtab.tmp" -+#define RMTABLCK ".rmtab.lock" -+ -+struct state_paths { -+ char *statefn; -+ char *tmpfn; -+ char *lockfn; -+}; -+ - /* Maximum number of security flavors on an export: */ - #define SECFLAVOR_COUNT 8 - -@@ -120,6 +115,10 @@ void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos); - void fendrmtabent(FILE *fp); - void frewindrmtabent(FILE *fp); - -+_Bool state_setup_basedir(const char *, const char *); -+int setup_state_path_names(const char *, const char *, const char *, const char *, struct state_paths *); -+void free_state_path_names(struct state_paths *); -+ - /* mydaemon */ - void daemon_init(bool fg); - void daemon_ready(void); -diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am -index 1048580..8936b0d 100644 ---- a/support/misc/Makefile.am -+++ b/support/misc/Makefile.am -@@ -1,6 +1,6 @@ - ## Process this file with automake to produce Makefile.in - - noinst_LIBRARIES = libmisc.a --libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c -+libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/support/misc/file.c b/support/misc/file.c -new file mode 100644 -index 0000000..63597df ---- /dev/null -+++ b/support/misc/file.c -@@ -0,0 +1,110 @@ -+/* -+ * Copyright 2009 Oracle. All rights reserved. -+ * Copyright 2017 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of nfs-utils. -+ * -+ * nfs-utils is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * nfs-utils is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with nfs-utils. If not, see . -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xlog.h" -+#include "misc.h" -+ -+/* -+ * Returns a dynamically allocated, '\0'-terminated buffer -+ * containing an appropriate pathname, or NULL if an error -+ * occurs. Caller must free the returned result with free(3). -+ */ -+__attribute__((__malloc__)) -+char * -+generic_make_pathname(const char *base, const char *leaf) -+{ -+ size_t size; -+ char *path; -+ int len; -+ -+ size = strlen(base) + strlen(leaf) + 2; -+ if (size > PATH_MAX) -+ return NULL; -+ -+ path = malloc(size); -+ if (path == NULL) -+ return NULL; -+ -+ len = snprintf(path, size, "%s/%s", base, leaf); -+ if ((len < 0) || ((size_t)len >= size)) { -+ free(path); -+ return NULL; -+ } -+ -+ return path; -+} -+ -+ -+/** -+ * generic_setup_basedir - set up basedir -+ * @progname: C string containing name of program, for error messages -+ * @parentdir: C string containing pathname to on-disk state, or NULL -+ * @base: character buffer to contain the basedir that is set up -+ * @baselen: size of @base in bytes -+ * -+ * This runs before logging is set up, so error messages are directed -+ * to stderr. -+ * -+ * Returns true and sets up our basedir, if @parentdir was valid -+ * and usable; otherwise false is returned. -+ */ -+_Bool -+generic_setup_basedir(const char *progname, const char *parentdir, char *base, -+ const size_t baselen) -+{ -+ static char buf[PATH_MAX]; -+ struct stat st; -+ char *path; -+ -+ /* First: test length of name and whether it exists */ -+ if ((strlen(parentdir) >= baselen) || (strlen(parentdir) >= PATH_MAX)) { -+ (void)fprintf(stderr, "%s: Directory name too long: %s", -+ progname, parentdir); -+ return false; -+ } -+ if (lstat(parentdir, &st) == -1) { -+ (void)fprintf(stderr, "%s: Failed to stat %s: %s", -+ progname, parentdir, strerror(errno)); -+ return false; -+ } -+ -+ /* Ensure we have a clean directory pathname */ -+ strncpy(buf, parentdir, sizeof(buf)); -+ path = dirname(buf); -+ if (*path == '.') { -+ (void)fprintf(stderr, "%s: Unusable directory %s", -+ progname, parentdir); -+ return false; -+ } -+ -+ xlog(D_CALL, "Using %s as the state directory", parentdir); -+ strcpy(base, parentdir); -+ return true; -+} -diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c -index e5e2579..9912afa 100644 ---- a/support/nfs/cacheio.c -+++ b/support/nfs/cacheio.c -@@ -27,6 +27,8 @@ - #include - #include - -+extern struct state_paths etab; -+ - void qword_add(char **bpp, int *lp, char *str) - { - char *bp = *bpp; -@@ -199,7 +201,7 @@ int qword_get_uint(char **bpp, unsigned int *anint) - } - - /* flush the kNFSd caches. -- * Set the flush time to the mtime of _PATH_ETAB or -+ * Set the flush time to the mtime of the etab state file or - * if force, to now. - * the caches to flush are: - * auth.unix.ip nfsd.export nfsd.fh -@@ -228,7 +230,7 @@ cache_flush(int force) - }; - now = time(0); - if (force || -- stat(_PATH_ETAB, &stb) != 0 || -+ stat(etab.statefn, &stb) != 0 || - stb.st_mtime > now) - stb.st_mtime = time(0); - -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index e717c1e..203efd2 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -533,7 +533,7 @@ retry: - * or from environment - */ - char *env = getenv(cb->value+1); -- if (env) -+ if (env && *env) - return env; - section = "environment"; - tag = cb->value + 1; -diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c -index 59dfbdf..2ecb2cc 100644 ---- a/support/nfs/rmtab.c -+++ b/support/nfs/rmtab.c -@@ -33,12 +33,14 @@ - - static FILE *rmfp = NULL; - -+extern struct state_paths rmtab; -+ - int - setrmtabent(char *type) - { - if (rmfp) - fclose(rmfp); -- rmfp = fsetrmtabent(_PATH_RMTAB, type); -+ rmfp = fsetrmtabent(rmtab.statefn, type); - return (rmfp != NULL); - } - -diff --git a/support/nsm/file.c b/support/nsm/file.c -index aafa755..52f5401 100644 ---- a/support/nsm/file.c -+++ b/support/nsm/file.c -@@ -88,6 +88,7 @@ - - #include "xlog.h" - #include "nsm.h" -+#include "misc.h" - - #define RPCARGSLEN (4 * (8 + 1)) - #define LINELEN (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1) -@@ -170,25 +171,7 @@ __attribute__((__malloc__)) - static char * - nsm_make_pathname(const char *directory) - { -- size_t size; -- char *path; -- int len; -- -- size = strlen(nsm_base_dirname) + strlen(directory) + 2; -- if (size > PATH_MAX) -- return NULL; -- -- path = malloc(size); -- if (path == NULL) -- return NULL; -- -- len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory); -- if (error_check(len, size)) { -- free(path); -- return NULL; -- } -- -- return path; -+ return generic_make_pathname(nsm_base_dirname, directory); - } - - /* -@@ -293,29 +276,8 @@ out: - _Bool - nsm_setup_pathnames(const char *progname, const char *parentdir) - { -- static char buf[PATH_MAX]; -- struct stat st; -- char *path; -- -- /* First: test length of name and whether it exists */ -- if (lstat(parentdir, &st) == -1) { -- (void)fprintf(stderr, "%s: Failed to stat %s: %s", -- progname, parentdir, strerror(errno)); -- return false; -- } -- -- /* Ensure we have a clean directory pathname */ -- strncpy(buf, parentdir, sizeof(buf)); -- path = dirname(buf); -- if (*path == '.') { -- (void)fprintf(stderr, "%s: Unusable directory %s", -- progname, parentdir); -- return false; -- } -- -- xlog(D_CALL, "Using %s as the state directory", parentdir); -- strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname)); -- return true; -+ return generic_setup_basedir(progname, parentdir, nsm_base_dirname, -+ PATH_MAX); - } - - /** -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -index 0d15b9f..eef53c4 100644 ---- a/systemd/Makefile.am -+++ b/systemd/Makefile.am -@@ -4,6 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in - - unit_files = \ - nfs-client.target \ -+ rpc_pipefs.target \ - \ - nfs-mountd.service \ - nfs-server.service \ -@@ -42,14 +43,23 @@ EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS) - unit_dir = /usr/lib/systemd/system - generator_dir = /usr/lib/systemd/system-generators - --EXTRA_PROGRAMS = nfs-server-generator -+EXTRA_PROGRAMS = nfs-server-generator rpc-pipefs-generator - genexecdir = $(generator_dir) -+ -+COMMON_SRCS = systemd.c systemd.h -+ -+nfs_server_generator_SOURCES = $(COMMON_SRCS) nfs-server-generator.c -+ -+rpc_pipefs_generator_SOURCES = $(COMMON_SRCS) rpc-pipefs-generator.c -+ - nfs_server_generator_LDADD = ../support/export/libexport.a \ - ../support/nfs/libnfs.a \ - ../support/misc/libmisc.a - -+rpc_pipefs_generator_LDADD = ../support/nfs/libnfs.a -+ - if INSTALL_SYSTEMD --genexec_PROGRAMS = nfs-server-generator -+genexec_PROGRAMS = nfs-server-generator rpc-pipefs-generator - install-data-hook: $(unit_files) - mkdir -p $(DESTDIR)/$(unitdir) - cp $(unit_files) $(DESTDIR)/$(unitdir) -diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service -index ddc324e..2bbcee6 100644 ---- a/systemd/nfs-blkmap.service -+++ b/systemd/nfs-blkmap.service -@@ -2,8 +2,8 @@ - Description=pNFS block layout mapping daemon - DefaultDependencies=no - Conflicts=umount.target --After=var-lib-nfs-rpc_pipefs.mount --Requires=var-lib-nfs-rpc_pipefs.mount -+After=rpc_pipefs.target -+Requires=rpc_pipefs.target - - PartOf=nfs-utils.service - -diff --git a/systemd/nfs-idmapd.service b/systemd/nfs-idmapd.service -index acca86b..f38fe52 100644 ---- a/systemd/nfs-idmapd.service -+++ b/systemd/nfs-idmapd.service -@@ -1,8 +1,8 @@ - [Unit] - Description=NFSv4 ID-name mapping service - DefaultDependencies=no --Requires=var-lib-nfs-rpc_pipefs.mount --After=var-lib-nfs-rpc_pipefs.mount local-fs.target -+Requires=rpc_pipefs.target -+After=rpc_pipefs.target local-fs.target - - BindsTo=nfs-server.service - -diff --git a/systemd/nfs-mountd.service b/systemd/nfs-mountd.service -index 15e828b..fec0399 100644 ---- a/systemd/nfs-mountd.service -+++ b/systemd/nfs-mountd.service -@@ -2,8 +2,9 @@ - Description=NFS Mount Daemon - DefaultDependencies=no - Requires=proc-fs-nfsd.mount -+Wants=network-online.target - After=proc-fs-nfsd.mount --After=network.target local-fs.target -+After=rpcbind.socket - BindsTo=nfs-server.service - - [Service] -diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c -index cc99969..737f109 100644 ---- a/systemd/nfs-server-generator.c -+++ b/systemd/nfs-server-generator.c -@@ -29,6 +29,7 @@ - #include "misc.h" - #include "nfslib.h" - #include "exportfs.h" -+#include "systemd.h" - - /* A simple "set of strings" to remove duplicates - * found in /etc/exports -@@ -55,38 +56,31 @@ static int is_unique(struct list **lp, char *path) - return 1; - } - --/* We need to convert a path name to a systemd unit -- * name. This requires some translation ('/' -> '-') -- * and some escaping. -- */ --static void systemd_escape(FILE *f, char *path) -+static int has_noauto_flag(char *path) - { -- while (*path == '/') -- path++; -- if (!*path) { -- /* "/" becomes "-", otherwise leading "/" is ignored */ -- fputs("-", f); -- return; -- } -- while (*path) { -- char c = *path++; -- -- if (c == '/') { -- /* multiple non-trailing slashes become '-' */ -- while (*path == '/') -- path++; -- if (*path) -- fputs("-", f); -- } else if (isalnum(c) || c == ':' || c == '.') -- fputc(c, f); -- else -- fprintf(f, "\\x%02x", c & 0xff); -+ FILE *fstab; -+ struct mntent *mnt; -+ -+ fstab = setmntent("/etc/fstab", "r"); -+ if (!fstab) -+ return 0; -+ -+ while ((mnt = getmntent(fstab)) != NULL) { -+ int l = strlen(mnt->mnt_dir); -+ if (strncmp(mnt->mnt_dir, path, l) != 0) -+ continue; -+ if (path[l] && path[l] != '/') -+ continue; -+ if (hasmntopt(mnt, "noauto")) -+ break; - } -+ fclose(fstab); -+ return mnt != NULL; - } - - int main(int argc, char *argv[]) - { -- char *path; -+ char *path, *spath; - char dirbase[] = "/nfs-server.service.d"; - char filebase[] = "/order-with-mounts.conf"; - nfs_export *exp; -@@ -124,6 +118,10 @@ int main(int argc, char *argv[]) - for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { - if (!is_unique(&list, exp->m_export.e_path)) - continue; -+ if (exp->m_export.e_mountpoint) -+ continue; -+ if (has_noauto_flag(exp->m_export.e_path)) -+ continue; - if (strchr(exp->m_export.e_path, ' ')) - fprintf(f, "RequiresMountsFor=\"%s\"\n", - exp->m_export.e_path); -@@ -141,9 +139,15 @@ int main(int argc, char *argv[]) - if (strcmp(mnt->mnt_type, "nfs") != 0 && - strcmp(mnt->mnt_type, "nfs4") != 0) - continue; -- fprintf(f, "Before= "); -- systemd_escape(f, mnt->mnt_dir); -- fprintf(f, ".mount\n"); -+ -+ spath = systemd_escape(mnt->mnt_dir, ".mount"); -+ if (!spath) { -+ fprintf(stderr, -+ "nfs-server-generator: convert path failed: %s\n", -+ mnt->mnt_dir); -+ continue; -+ } -+ fprintf(f, "Before=%s\n", spath); - } - - fclose(fstab); -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 5be5de6..e6b8f58 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -3,12 +3,12 @@ Description=NFS server and services - DefaultDependencies=no - Requires= network.target proc-fs-nfsd.mount - Requires= nfs-mountd.service --Wants=rpcbind.socket -+Wants=rpcbind.socket network-online.target - Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service - - After= local-fs.target --After= network.target proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service -+After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service - After= nfs-idmapd.service rpc-statd.service - Before= rpc-statd-notify.service - -diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man -index 91c49a0..189b052 100644 ---- a/systemd/nfs.conf.man -+++ b/systemd/nfs.conf.man -@@ -96,6 +96,18 @@ value, which can be one or more from the list - .BR all . - When a list is given, the members should be comma-separated. - .TP -+.B general -+Recognized values: -+.BR pipefs-directory . -+ -+See -+.BR blkmapd (8), -+.BR rpc.idmapd (8), -+and -+.BR rpc.gssd (8) -+for details. -+ -+.TP - .B nfsdcltrack - Recognized values: - .BR storagedir . -@@ -154,6 +166,13 @@ section, are used to configure mountd. See - .BR rpc.mountd (8) - for details. - -+The -+.B state-directory-path -+value in the -+.B [mountd] -+section is also used by -+.BR exportfs (8). -+ - .TP - .B statd - Recognized values: -@@ -198,7 +217,6 @@ Recognized values: - .BR limit-to-legacy-enctypes , - .BR context-timeout , - .BR rpc-timeout , --.BR pipefs-directory , - .BR keytab-file , - .BR cred-cache-directory , - .BR preferred-realm . -diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in -index b353027..6807db3 100644 ---- a/systemd/rpc-gssd.service.in -+++ b/systemd/rpc-gssd.service.in -@@ -2,8 +2,8 @@ - Description=RPC security service for NFS client and server - DefaultDependencies=no - Conflicts=umount.target --Requires=var-lib-nfs-rpc_pipefs.mount --After=var-lib-nfs-rpc_pipefs.mount -+Requires=rpc_pipefs.target -+After=rpc_pipefs.target - - ConditionPathExists=@_sysconfdir@/krb5.keytab - -diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c -new file mode 100644 -index 0000000..66addb9 ---- /dev/null -+++ b/systemd/rpc-pipefs-generator.c -@@ -0,0 +1,138 @@ -+/* -+ * rpc-pipefs-generator: -+ * systemd generator to create ordering dependencies between -+ * nfs services and the rpc_pipefs mountpoint -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "nfslib.h" -+#include "conffile.h" -+#include "systemd.h" -+ -+#define RPC_PIPEFS_DEFAULT "/var/lib/nfs/rpc_pipefs" -+char *conf_path = NFS_CONFFILE; -+ -+static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit, -+ const char *dirname) -+{ -+ char *path; -+ FILE *f; -+ -+ path = malloc(strlen(dirname) + 1 + strlen(pipefs_unit)); -+ if (!path) -+ return 1; -+ sprintf(path, "%s/%s", dirname, pipefs_unit); -+ f = fopen(path, "w"); -+ if (!f) -+ return 1; -+ -+ fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); -+ fprintf(f, "Description=RPC Pipe File System\n"); -+ fprintf(f, "DefaultDependencies=no\n"); -+ fprintf(f, "After=systemd-tmpfiles-setup.service\n"); -+ fprintf(f, "Conflicts=umount.target\n"); -+ fprintf(f, "\n[Mount]\n"); -+ fprintf(f, "What=sunrpc\n"); -+ fprintf(f, "Where=%s\n", pipefs_path); -+ fprintf(f, "Type=rpc_pipefs\n"); -+ -+ fclose(f); -+ return 0; -+} -+ -+static -+int generate_target(char *pipefs_path, const char *dirname) -+{ -+ char *path; -+ char filebase[] = "/rpc_pipefs.target"; -+ char *pipefs_unit; -+ FILE *f; -+ int ret = 0; -+ -+ pipefs_unit = systemd_escape(pipefs_path, ".mount"); -+ if (!pipefs_unit) -+ return 1; -+ -+ ret = generate_mount_unit(pipefs_path, pipefs_unit, dirname); -+ if (ret) -+ return ret; -+ -+ path = malloc(strlen(dirname) + 1 + sizeof(filebase)); -+ if (!path) -+ return 2; -+ sprintf(path, "%s", dirname); -+ mkdir(path, 0755); -+ strcat(path, filebase); -+ f = fopen(path, "w"); -+ if (!f) -+ return 1; -+ -+ fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); -+ fprintf(f, "Requires=%s\n", pipefs_unit); -+ fprintf(f, "After=%s\n", pipefs_unit); -+ fclose(f); -+ -+ return 0; -+} -+ -+static int is_non_pipefs_mountpoint(char *path) -+{ -+ FILE *mtab; -+ struct mntent *mnt; -+ -+ mtab = setmntent("/etc/mtab", "r"); -+ if (!mtab) -+ return 0; -+ -+ while ((mnt = getmntent(mtab)) != NULL) { -+ if (strlen(mnt->mnt_dir) != strlen(path)) -+ continue; -+ if (strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir))) -+ continue; -+ if (strncmp(mnt->mnt_type, "rpc_pipefs", strlen(mnt->mnt_type))) -+ break; -+ } -+ fclose(mtab); -+ return mnt != NULL; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int ret; -+ char *s; -+ -+ /* Avoid using any external services */ -+ xlog_syslog(0); -+ -+ if (argc != 4 || argv[1][0] != '/') { -+ fprintf(stderr, "rpc-pipefs-generator: create systemd dependencies for nfs services\n"); -+ fprintf(stderr, "Usage: normal-dir early-dir late-dir\n"); -+ exit(1); -+ } -+ -+ conf_init(); -+ s = conf_get_str("general", "pipefs-directory"); -+ if (!s) -+ exit(0); -+ if (strlen(s) == strlen(RPC_PIPEFS_DEFAULT) && -+ strcmp(s, RPC_PIPEFS_DEFAULT) == 0) -+ exit(0); -+ -+ if (is_non_pipefs_mountpoint(s)) -+ exit(1); -+ -+ ret = generate_target(s, argv[1]); -+ exit(ret); -+} -diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service -index 7bfc9b1..f54d4c5 100644 ---- a/systemd/rpc-statd-notify.service -+++ b/systemd/rpc-statd-notify.service -@@ -1,7 +1,7 @@ - [Unit] - Description=Notify NFS peers of a restart - DefaultDependencies=no --Requires=network.target -+Wants=network-online.target - After=local-fs.target network.target nss-lookup.target - - # if we run an nfs server, it needs to be running before we -diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service -index 60d600f..8cef022 100644 ---- a/systemd/rpc-statd.service -+++ b/systemd/rpc-statd.service -@@ -3,7 +3,8 @@ Description=NFS status monitor for NFSv2/3 locking. - DefaultDependencies=no - Conflicts=umount.target - Requires=nss-lookup.target rpcbind.socket --After=network.target nss-lookup.target rpcbind.socket -+Wants=network-online.target -+After=nss-lookup.target rpcbind.socket - - PartOf=nfs-utils.service - -diff --git a/systemd/rpc-svcgssd.service b/systemd/rpc-svcgssd.service -index 7187e3c..cb2bcd4 100644 ---- a/systemd/rpc-svcgssd.service -+++ b/systemd/rpc-svcgssd.service -@@ -1,8 +1,7 @@ - [Unit] - Description=RPC security service for NFS server - DefaultDependencies=no --Requires=var-lib-nfs-rpc_pipefs.mount --After=var-lib-nfs-rpc_pipefs.mount local-fs.target -+After=local-fs.target - PartOf=nfs-server.service - PartOf=nfs-utils.service - -diff --git a/systemd/rpc_pipefs.target b/systemd/rpc_pipefs.target -new file mode 100644 -index 0000000..01d4d27 ---- /dev/null -+++ b/systemd/rpc_pipefs.target -@@ -0,0 +1,3 @@ -+[Unit] -+Requires=var-lib-nfs-rpc_pipefs.mount -+After=var-lib-nfs-rpc_pipefs.mount -diff --git a/systemd/systemd.c b/systemd/systemd.c -new file mode 100644 -index 0000000..17820d4 ---- /dev/null -+++ b/systemd/systemd.c -@@ -0,0 +1,133 @@ -+/* -+ * Helper functions for systemd generators in nfs-utils. -+ * -+ * Currently just systemd_escape(). -+ */ -+ -+#include -+#include -+#include -+#include -+ -+static const char hex[16] = -+{ -+ '0', '1', '2', '3', '4', '5', '6', '7', -+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', -+}; -+ -+/* -+ * determine length of the string that systemd_escape() needs to allocate -+ */ -+static int systemd_len(char *path) -+{ -+ char *p; -+ int len = 0; -+ -+ p = path; -+ while (*p == '/') -+ /* multiple leading "/" are ignored */ -+ p++; -+ -+ if (!*p) -+ /* root directory "/" becomes is encoded as a single "-" */ -+ return 1; -+ -+ if (*p == '.') -+ /* -+ * replace "." with "\x2d" escape sequence if -+ * it's the first character in escaped path -+ * */ -+ len += 4; -+ -+ while (*p) { -+ unsigned char c = *p++; -+ -+ if (c == '/') { -+ /* multiple non-trailing slashes become '-' */ -+ while (*p == '/') -+ p++; -+ if (*p) -+ len++; -+ } else if (isalnum(c) || c == ':' || c == '.' || c == '_') -+ /* these characters are not replaced */ -+ len++; -+ else -+ /* replace with "\x2d" escape sequence */ -+ len += 4; -+ } -+ -+ return len; -+} -+ -+/* -+ * convert c to "\x2d" escape sequence and append to string -+ * at position p, advancing p -+ */ -+static char *hexify(unsigned char c, char *p) -+{ -+ *p++ = '\\'; -+ *p++ = 'x'; -+ *p++ = hex[c >> 4]; -+ *p++ = hex[c & 0xf]; -+ return p; -+} -+ -+/* -+ * convert a path to a unit name according to the logic in systemd.unit(5): -+ * -+ * Basically, given a path, "/" is replaced by "-", and all other -+ * characters which are not ASCII alphanumerics are replaced by C-style -+ * "\x2d" escapes (except that "_" is never replaced and "." is only -+ * replaced when it would be the first character in the escaped path). -+ * The root directory "/" is encoded as single dash, while otherwise the -+ * initial and ending "/" are removed from all paths during -+ * transformation. -+ * -+ * NB: Although the systemd.unit(5) doesn't mention it, the ':' character -+ * is not escaped. -+ */ -+char *systemd_escape(char *path, char *suffix) -+{ -+ char *result; -+ char *p; -+ int len; -+ -+ len = systemd_len(path); -+ result = malloc(len + strlen(suffix) + 1); -+ p = result; -+ while (*path == '/') -+ /* multiple leading "/" are ignored */ -+ path++; -+ if (!*path) { -+ /* root directory "/" becomes is encoded as a single "-" */ -+ *p++ = '-'; -+ goto out; -+ } -+ if (*path == '.') -+ /* -+ * replace "." with "\x2d" escape sequence if -+ * it's the first character in escaped path -+ * */ -+ p = hexify(*path++, p); -+ -+ while (*path) { -+ unsigned char c = *path++; -+ -+ if (c == '/') { -+ /* multiple non-trailing slashes become '-' */ -+ while (*path == '/') -+ path++; -+ if (*path) -+ *p++ = '-'; -+ } else if (isalnum(c) || c == ':' || c == '.' || c == '_') -+ /* these characters are not replaced */ -+ *p++ = c; -+ else -+ /* replace with "\x2d" escape sequence */ -+ p = hexify(c, p); -+ } -+ -+out: -+ sprintf(p, "%s", suffix); -+ return result; -+} -diff --git a/systemd/systemd.h b/systemd/systemd.h -new file mode 100644 -index 0000000..25235ec ---- /dev/null -+++ b/systemd/systemd.h -@@ -0,0 +1,6 @@ -+#ifndef SYSTEMD_H -+#define SYSTEMD_H -+ -+char *systemd_escape(char *path, char *suffix); -+ -+#endif /* SYSTEMD_H */ -diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man -index 914b80f..4b3d3f0 100644 ---- a/utils/blkmapd/blkmapd.man -+++ b/utils/blkmapd/blkmapd.man -@@ -43,9 +43,24 @@ Performs device discovery only then exits. - Runs - .B blkmapd - in the foreground and sends output to stderr (as opposed to syslogd) -+.SH CONFIGURATION FILE -+The -+.B blkmapd -+daemon recognizes the following value from the -+.B [general] -+section of the -+.I /etc/nfs.conf -+configuration file: -+.TP -+.B pipefs-directory -+Tells -+.B blkmapd -+where to look for the rpc_pipefs filesystem. The default value is -+.IR /var/lib/nfs/rpc_pipefs . - .SH SEE ALSO - .BR nfs (5), --.BR dmsetup (8) -+.BR dmsetup (8), -+.BR nfs.conf (5) - .sp - RFC 5661 for the NFS version 4.1 specification. - .br -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index 8eb3fd0..d2da764 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -50,20 +50,36 @@ - #include - #include - -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif /* HAVE_CONFIG_H */ -+ - #include "device-discovery.h" - #include "xcommon.h" -+#include "nfslib.h" -+#include "conffile.h" - - #define EVENT_SIZE (sizeof(struct inotify_event)) - #define EVENT_BUFSIZE (1024 * EVENT_SIZE) - --#define BL_PIPE_FILE "/var/lib/nfs/rpc_pipefs/nfs/blocklayout" --#define NFSPIPE_DIR "/var/lib/nfs/rpc_pipefs/nfs" - #define RPCPIPE_DIR "/var/lib/nfs/rpc_pipefs" - #define PID_FILE "/var/run/blkmapd.pid" - -+#define CONF_SAVE(w, f) do { \ -+ char *p = f; \ -+ if (p != NULL) \ -+ (w) = p; \ -+} while (0) -+ -+static char bl_pipe_file[PATH_MAX]; -+static char nfspipe_dir[PATH_MAX]; -+static char rpcpipe_dir[PATH_MAX]; -+ - struct bl_disk *visible_disk_list; - int bl_watch_fd, bl_pipe_fd, nfs_pipedir_wfd, rpc_pipedir_wfd; - int pidfd = -1; -+char *conf_path = NULL; -+ - - struct bl_disk_path *bl_get_path(const char *filepath, - struct bl_disk_path *paths) -@@ -358,8 +374,8 @@ static void bl_rpcpipe_cb(void) - continue; - if (event->mask & IN_CREATE) { - BL_LOG_WARNING("nfs pipe dir created\n"); -- bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd); -- bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR); -+ bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd); -+ bl_pipe_fd = open(bl_pipe_file, O_RDWR); - } else if (event->mask & IN_DELETE) { - BL_LOG_WARNING("nfs pipe dir deleted\n"); - inotify_rm_watch(bl_watch_fd, nfs_pipedir_wfd); -@@ -372,7 +388,7 @@ static void bl_rpcpipe_cb(void) - continue; - if (event->mask & IN_CREATE) { - BL_LOG_WARNING("blocklayout pipe file created\n"); -- bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR); -+ bl_pipe_fd = open(bl_pipe_file, O_RDWR); - if (bl_pipe_fd < 0) - BL_LOG_ERR("open %s failed: %s\n", - event->name, strerror(errno)); -@@ -437,6 +453,19 @@ int main(int argc, char **argv) - { - int opt, dflag = 0, fg = 0, ret = 1; - char pidbuf[64]; -+ char *xrpcpipe_dir = NULL; -+ -+ strncpy(rpcpipe_dir, RPCPIPE_DIR, sizeof(rpcpipe_dir)); -+ conf_path = NFS_CONFFILE; -+ conf_init(); -+ CONF_SAVE(xrpcpipe_dir, conf_get_str("general", "pipefs-directory")); -+ if (xrpcpipe_dir != NULL) -+ strlcpy(rpcpipe_dir, xrpcpipe_dir, sizeof(rpcpipe_dir)); -+ -+ strncpy(nfspipe_dir, rpcpipe_dir, sizeof(nfspipe_dir)); -+ strlcat(nfspipe_dir, "/nfs", sizeof(nfspipe_dir)); -+ strncpy(bl_pipe_file, rpcpipe_dir, sizeof(bl_pipe_file)); -+ strlcat(bl_pipe_file, "/nfs/blocklayout", sizeof(bl_pipe_file)); - - while ((opt = getopt(argc, argv, "hdf")) != -1) { - switch (opt) { -@@ -496,12 +525,12 @@ int main(int argc, char **argv) - } - - /* open pipe file */ -- bl_watch_dir(RPCPIPE_DIR, &rpc_pipedir_wfd); -- bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd); -+ bl_watch_dir(rpcpipe_dir, &rpc_pipedir_wfd); -+ bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd); - -- bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR); -+ bl_pipe_fd = open(bl_pipe_file, O_RDWR); - if (bl_pipe_fd < 0) -- BL_LOG_ERR("open pipe file %s failed: %s\n", BL_PIPE_FILE, strerror(errno)); -+ BL_LOG_ERR("open pipe file %s failed: %s\n", bl_pipe_file, strerror(errno)); - - while (1) { - /* discover device when needed */ -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 61dddfb..02d5b6d 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -52,6 +52,8 @@ static const char *lockfile = EXP_LOCKFILE; - static int _lockfd = -1; - char *conf_path = NFS_CONFFILE; - -+struct state_paths etab; -+ - /* - * If we aren't careful, changes made by exportfs can be lost - * when multiple exports process run at once: -@@ -95,6 +97,7 @@ main(int argc, char **argv) - int f_ignore = 0; - int i, c; - int force_flush = 0; -+ char *s; - - if ((progname = strrchr(argv[0], '/')) != NULL) - progname++; -@@ -108,6 +111,11 @@ main(int argc, char **argv) - conf_init(); - xlog_from_conffile("exportfs"); - -+ /* NOTE: following uses "mountd" section of nfs.conf !!!! */ -+ s = conf_get_str("mountd", "state-directory-path"); -+ if (s && !state_setup_basedir(argv[0], s)) -+ exit(1); -+ - while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) { - switch(c) { - case 'a': -@@ -159,13 +167,17 @@ main(int argc, char **argv) - xlog(L_ERROR, "-r and -u are incompatible"); - return 1; - } -+ if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) -+ return 1; - if (optind == argc && ! f_all) { - if (force_flush) { - cache_flush(1); -+ free_state_path_names(&etab); - return 0; - } else { - xtab_export_read(); - dump(f_verbose, f_export_format); -+ free_state_path_names(&etab); - return 0; - } - } -@@ -206,6 +218,7 @@ main(int argc, char **argv) - } - xtab_export_write(); - cache_flush(force_flush); -+ free_state_path_names(&etab); - - return export_errno; - } -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 45b6d83..91d3589 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -148,6 +148,29 @@ options. - .TP - .B -s - Display the current export list suitable for /etc/exports. -+ -+.SH CONFIGURATION FILE -+The -+.B [exportfs] -+section of the -+.I /etc/nfs.conf -+configuration file can contain a -+.B debug -+value, which can be one or more from the list -+.BR general , -+.BR call , -+.BR auth , -+.BR parse , -+.BR all . -+When a list is given, the members should be comma-separated. -+ -+.B exportfs -+will also recognize the -+.B state-directory-path -+value from the -+.B [mountd] -+section. -+ - .SH DISCUSSION - .SS Exporting Directories - The first synopsis shows how to invoke -diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man -index 0c516fa..9efa29f 100644 ---- a/utils/exportfs/nfsd.man -+++ b/utils/exportfs/nfsd.man -@@ -105,11 +105,6 @@ clients have for different filesystems. - The caches are: - - .TP --.B auth.domain --This cache maps the name of a client (or domain) to an internal data --structure. The only access that is possible is to flush the cache. -- --.TP - .B auth.unix.ip - This cache contains a mapping from IP address to the name of the - authentication domain that the ipaddress should be treated as part of. -@@ -133,7 +128,8 @@ are: - .B flush - When a number of seconds since epoch (1 Jan 1970) is written to this - file, all entries in the cache that were last updated before that file --become invalidated and will be flushed out. Writing 1 will flush -+become invalidated and will be flushed out. Writing a time in the -+future (in seconds since epoch) will flush - everything. This is the only file that will always be present. - - .TP -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 4d18d35..28f9649 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -87,6 +87,7 @@ int root_uses_machine_creds = 1; - unsigned int context_timeout = 0; - unsigned int rpc_timeout = 5; - char *preferred_realm = NULL; -+char *ccachedir = NULL; - /* Avoid DNS reverse lookups on server names */ - static bool avoid_dns = true; - int thread_started = false; -@@ -837,18 +838,9 @@ usage(char *progname) - exit(1); - } - --int --main(int argc, char *argv[]) -+inline static void -+read_gss_conf(void) - { -- int fg = 0; -- int verbosity = 0; -- int rpc_verbosity = 0; -- int opt; -- int i; -- extern char *optarg; -- char *progname; -- char *ccachedir = NULL; -- struct event sighup_ev; - char *s; - - conf_init(); -@@ -865,6 +857,10 @@ main(int argc, char *argv[]) - s = conf_get_str("gssd", "pipefs-directory"); - if (!s) - s = conf_get_str("general", "pipefs-directory"); -+ else -+ printerr(0, "WARNING: Specifying pipefs-directory in the [gssd] " -+ "section of %s is deprecated. Use the [general] " -+ "section instead.", NFS_CONFFILE); - if (s) - pipefs_path = s; - s = conf_get_str("gssd", "keytab-file"); -@@ -877,6 +873,22 @@ main(int argc, char *argv[]) - if (s) - preferred_realm = s; - -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ int fg = 0; -+ int verbosity = 0; -+ int rpc_verbosity = 0; -+ int opt; -+ int i; -+ extern char *optarg; -+ char *progname; -+ struct event sighup_ev; -+ -+ read_gss_conf(); -+ - while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { - switch (opt) { - case 'f': -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 87eef02..e620f0d 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -335,10 +335,6 @@ Equivalent to - Equivalent to - .BR -t . - .TP --.B pipefs-directory --Equivalent to --.BR -p . --.TP - .B keytab-file - Equivalent to - .BR -k . -@@ -350,6 +346,14 @@ Equivalent to - .B preferred-realm - Equivalent to - .BR -R . -+.P -+In addtion, the following value is recognized from the -+.B [general] -+section: -+.TP -+.B pipefs-directory -+Equivalent to -+.BR -p . - - .SH SEE ALSO - .BR rpc.svcgssd (8), -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index d74d372..4fc81c3 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -729,10 +729,18 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - char *target = NULL; - char *service = NULL; - char *enctypes = NULL; -+ char *upcall_str; -+ char *pbuf = info->lbuf; - - printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); - -- for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) { -+ upcall_str = strdup(info->lbuf); -+ if (upcall_str == NULL) { -+ printerr(0, "ERROR: malloc failure\n"); -+ goto out_nomem; -+ } -+ -+ while ((p = strsep(&pbuf, " "))) { - if (!strncmp(p, "mech=", strlen("mech="))) - mech = p + strlen("mech="); - else if (!strncmp(p, "uid=", strlen("uid="))) -@@ -748,7 +756,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - if (!mech || strlen(mech) < 1) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to find gss mechanism name " -- "in upcall string '%s'\n", info->lbuf); -+ "in upcall string '%s'\n", upcall_str); - goto out; - } - -@@ -761,7 +769,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - if (!uidstr) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to find uid " -- "in upcall string '%s'\n", info->lbuf); -+ "in upcall string '%s'\n", upcall_str); - goto out; - } - -@@ -774,7 +782,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - if (target && strlen(target) < 1) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to parse target name " -- "in upcall string '%s'\n", info->lbuf); -+ "in upcall string '%s'\n", upcall_str); - goto out; - } - -@@ -789,7 +797,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - if (service && strlen(service) < 1) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to parse service type " -- "in upcall string '%s'\n", info->lbuf); -+ "in upcall string '%s'\n", upcall_str); - goto out; - } - -@@ -802,6 +810,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - do_error_downcall(clp->gssd_fd, uid, -EACCES); - } - out: -+ free(upcall_str); -+out_nomem: - free(info); - return; - } -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index f4e083a..56bf67e 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -166,7 +166,7 @@ static uid_t nobodyuid; - static gid_t nobodygid; - - /* Used by conffile.c in libnfs.a */ --char *conf_path; -+char *conf_path = NULL; - - static int - flush_nfsd_cache(char *path, time_t now) -@@ -220,7 +220,6 @@ main(int argc, char **argv) - int ret; - char *progname; - -- conf_path = _PATH_IDMAPDCONF; - nobodyuser = NFS4NOBODY_USER; - nobodygroup = NFS4NOBODY_GROUP; - strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir)); -@@ -234,8 +233,11 @@ main(int argc, char **argv) - #define GETOPTSTR "hvfd:p:U:G:c:CS" - opterr=0; /* Turn off error messages */ - while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { -- if (opt == 'c') -+ if (opt == 'c') { -+ warnx("-c is deprecated and may be removed in the " -+ "future. See idmapd(8)."); - conf_path = optarg; -+ } - if (opt == '?') { - if (strchr(GETOPTSTR, optopt)) - warnx("'-%c' option requires an argument.", optopt); -@@ -247,17 +249,33 @@ main(int argc, char **argv) - } - optind = 1; - -- if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) { -- warn("Skipping configuration file \"%s\"", conf_path); -- conf_path = NULL; -+ if (conf_path) { /* deprecated -c option was specified */ -+ if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) { -+ warn("Skipping configuration file \"%s\"", conf_path); -+ conf_path = NULL; -+ } else { -+ conf_init(); -+ verbose = conf_get_num("General", "Verbosity", 0); -+ cache_entry_expiration = conf_get_num("General", -+ "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); -+ CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); -+ if (xpipefsdir != NULL) -+ strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); -+ CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); -+ CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); -+ } - } else { -+ conf_path = NFS_CONFFILE; - conf_init(); -- verbose = conf_get_num("General", "Verbosity", 0); -- cache_entry_expiration = conf_get_num("General", -- "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); - CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); - if (xpipefsdir != NULL) - strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); -+ -+ conf_path = _PATH_IDMAPDCONF; -+ conf_init(); -+ verbose = conf_get_num("General", "Verbosity", 0); -+ cache_entry_expiration = conf_get_num("General", -+ "cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY); - CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); - CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); - } -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index d4ab894..5f34d2b 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -73,11 +73,28 @@ The default value is \&"/var/lib/nfs/rpc_pipefs\&". - .It Fl c Ar path - Use configuration file - .Ar path . -+This option is deprecated. - .It Fl C - Client-only: perform no idmapping for any NFS server, even if one is detected. - .It Fl S - Server-only: perform no idmapping for any NFS client, even if one is detected. - .El -+.Sh CONFIGURATION FILES -+.Nm -+recognizes the following value from the -+.Sy [general] -+section of the -+.Pa /etc/nfs.conf -+configuration file: -+.Bl -tag -width Ds_imagedir -+.It Sy pipefs-directory -+Equivalent to -+.Sy -p . -+.El -+.Pp -+All other settings related to id mapping are found in the -+.Pa /etc/idmapd.conf -+configuration file. - .Sh EXAMPLES - .Cm rpc.idmapd -f -vvv - .Pp -@@ -94,9 +111,11 @@ messages to console, and with a verbosity level of 3. - .\" This next request is for sections 1, 6, 7 & 8 only. - .\" .Sh ENVIRONMENT - .Sh FILES --.Pa /etc/idmapd.conf -+.Pa /etc/idmapd.conf , -+.Pa /etc/nfs.conf - .Sh SEE ALSO - .Xr idmapd.conf 5 , -+.Xr nfs.conf 5 , - .Xr nfsidmap 8 - .\".Sh SEE ALSO - .\".Xr nylon.conf 4 -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 7dceb2d..281e935 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -804,6 +805,7 @@ int start_statd(void) - pid_t pid = fork(); - switch (pid) { - case 0: /* child */ -+ setgroups(0, NULL); - setgid(0); - setuid(0); - execle(START_STATD, START_STATD, NULL, envp); -@@ -1638,6 +1640,7 @@ int nfs_options2pmap(struct mount_options *options, - struct pmap *nfs_pmap, struct pmap *mnt_pmap) - { - struct nfs_version version; -+ memset(&version, 0, sizeof(version)); - - if (!nfs_nfs_program(options, &nfs_pmap->pm_prog)) - return 0; -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 387d734..a9ff95d 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -517,6 +517,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4) - unsigned long protocol; - struct pmap mnt_pmap; - -+ /* initialize structs */ -+ memset(&nfs_pmap, 0, sizeof(struct pmap)); -+ memset(&mnt_pmap, 0, sizeof(struct pmap)); -+ - /* - * Version and transport negotiation is not required - * and does not work for RDMA mounts. -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index d065830..8299256 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -41,6 +41,8 @@ static nfs_client my_client; - - extern int use_ipaddr; - -+extern struct state_paths etab; -+ - void - auth_init(void) - { -@@ -84,10 +86,10 @@ auth_reload() - static unsigned int counter; - int fd; - -- if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) { -- xlog(L_FATAL, "couldn't open %s", _PATH_ETAB); -+ if ((fd = open(etab.statefn, O_RDONLY)) < 0) { -+ xlog(L_FATAL, "couldn't open %s", etab.statefn); - } else if (fstat(fd, &stb) < 0) { -- xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB); -+ xlog(L_FATAL, "couldn't stat %s", etab.statefn); - close(fd); - } else if (last_fd != -1 && stb.st_ino == last_inode) { - /* We opened the etab file before, and its inode -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 61699e6..bbadfaf 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -29,6 +29,7 @@ - #include "mountd.h" - #include "rpcmisc.h" - #include "pseudoflavors.h" -+#include "nfslib.h" - - extern void my_svc_run(void); - -@@ -40,6 +41,9 @@ int reverse_resolve = 0; - int manage_gids; - int use_ipaddr = -1; - -+struct state_paths etab; -+struct state_paths rmtab; -+ - char *conf_path = NFS_CONFFILE; - - /* PRC: a high-availability callout program can be specified with -H -@@ -110,8 +114,8 @@ unregister_services (void) - static void - cleanup_lockfiles (void) - { -- unlink(_PATH_ETABLCK); -- unlink(_PATH_RMTABLCK); -+ unlink(etab.lockfn); -+ unlink(rmtab.lockfn); - } - - /* Wait for all worker child processes to exit and reap them */ -@@ -181,6 +185,8 @@ fork_workers(void) - wait_for_workers(); - unregister_services(); - cleanup_lockfiles(); -+ free_state_path_names(&etab); -+ free_state_path_names(&rmtab); - xlog(L_NOTICE, "mountd: no more workers, exiting\n"); - exit(0); - } -@@ -198,6 +204,8 @@ killer (int sig) - wait_for_workers(); - } - cleanup_lockfiles(); -+ free_state_path_names(&etab); -+ free_state_path_names(&rmtab); - xlog (L_NOTICE, "Caught signal %d, un-registering and exiting.", sig); - exit(0); - } -@@ -656,7 +664,6 @@ get_exportlist(void) - int - main(int argc, char **argv) - { -- char *state_dir = NFS_STATEDIR; - char *progname; - char *s; - unsigned int listeners = 0; -@@ -684,8 +691,8 @@ main(int argc, char **argv) - ha_callout_prog = conf_get_str("mountd", "ha-callout"); - - s = conf_get_str("mountd", "state-directory-path"); -- if (s) -- state_dir = s; -+ if (s && !state_setup_basedir(argv[0], s)) -+ exit(1); - - /* NOTE: following uses "nfsd" section of nfs.conf !!!! */ - if (conf_get_bool("nfsd", "udp", NFSCTL_UDPISSET(_rpcprotobits))) -@@ -758,7 +765,8 @@ main(int argc, char **argv) - reverse_resolve = 1; - break; - case 's': -- state_dir = xstrdup(optarg); -+ if (!state_setup_basedir(argv[0], optarg)) -+ exit(1); - break; - case 't': - num_threads = atoi (optarg); -@@ -790,11 +798,10 @@ main(int argc, char **argv) - fprintf(stderr, "%s: No protocol versions specified!\n", progname); - usage(progname, 1); - } -- if (chdir(state_dir)) { -- fprintf(stderr, "%s: chdir(%s) failed: %s\n", -- progname, state_dir, strerror(errno)); -- exit(1); -- } -+ if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) -+ return 1; -+ if (!setup_state_path_names(progname, RMTAB, RMTABTMP, RMTABLCK, &rmtab)) -+ return 1; - - if (getrlimit (RLIMIT_NOFILE, &rlim) != 0) - fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n", -@@ -888,6 +895,8 @@ main(int argc, char **argv) - - xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n"); - unregister_services(); -+ free_state_path_names(&etab); -+ free_state_path_names(&rmtab); - exit(1); - } - -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index 9f0a51f..9978afc 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -144,7 +144,7 @@ Instead, mount the nfsd filesystem on - .IR /proc/fs/nfsd . - .TP - .BI "\-s," "" " \-\-state\-directory\-path " directory --Specify a directory in which to place statd state information. -+Specify a directory in which to place state information (etab and rmtab). - If this option is not specified the default of - .I /var/lib/nfs - is used. -diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c -index 527377f..3ae0dbb 100644 ---- a/utils/mountd/rmtab.c -+++ b/utils/mountd/rmtab.c -@@ -28,6 +28,8 @@ - - extern int reverse_resolve; - -+extern struct state_paths rmtab; -+ - /* If new path is a link do not destroy it but place the - * file where the link points. - */ -@@ -59,7 +61,7 @@ mountlist_add(char *host, const char *path) - int lockid; - long pos; - -- if ((lockid = xflock(_PATH_RMTABLCK, "a")) < 0) -+ if ((lockid = xflock(rmtab.lockfn, "a")) < 0) - return; - setrmtabent("r+"); - while ((rep = getrmtabent(1, &pos)) != NULL) { -@@ -99,13 +101,13 @@ mountlist_del(char *hname, const char *path) - int lockid; - int match; - -- if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0) -+ if ((lockid = xflock(rmtab.lockfn, "w")) < 0) - return; - if (!setrmtabent("r")) { - xfunlock(lockid); - return; - } -- if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) { -+ if (!(fp = fsetrmtabent(rmtab.tmpfn, "w"))) { - endrmtabent(); - xfunlock(lockid); - return; -@@ -121,9 +123,9 @@ mountlist_del(char *hname, const char *path) - if (!match || rep->r_count) - fputrmtabent(fp, rep, NULL); - } -- if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) { -+ if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) { - xlog(L_ERROR, "couldn't rename %s to %s", -- _PATH_RMTABTMP, _PATH_RMTAB); -+ rmtab.tmpfn, rmtab.statefn); - } - endrmtabent(); /* close & unlink */ - fendrmtabent(fp); -@@ -138,7 +140,7 @@ mountlist_del_all(const struct sockaddr *sap) - FILE *fp; - int lockid; - -- if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0) -+ if ((lockid = xflock(rmtab.lockfn, "w")) < 0) - return; - hostname = host_canonname(sap); - if (hostname == NULL) { -@@ -151,7 +153,7 @@ mountlist_del_all(const struct sockaddr *sap) - if (!setrmtabent("r")) - goto out_free; - -- if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) -+ if (!(fp = fsetrmtabent(rmtab.tmpfn, "w"))) - goto out_close; - - while ((rep = getrmtabent(1, NULL)) != NULL) { -@@ -160,9 +162,9 @@ mountlist_del_all(const struct sockaddr *sap) - continue; - fputrmtabent(fp, rep, NULL); - } -- if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) { -+ if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) { - xlog(L_ERROR, "couldn't rename %s to %s", -- _PATH_RMTABTMP, _PATH_RMTAB); -+ rmtab.tmpfn, rmtab.statefn); - } - fendrmtabent(fp); - out_close: -@@ -195,11 +197,11 @@ mountlist_list(void) - struct stat stb; - int lockid; - -- if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0) -+ if ((lockid = xflock(rmtab.lockfn, "r")) < 0) - return NULL; -- if (stat(_PATH_RMTAB, &stb) < 0) { -+ if (stat(rmtab.statefn, &stb) < 0) { - xlog(L_ERROR, "can't stat %s: %s", -- _PATH_RMTAB, strerror(errno)); -+ rmtab.statefn, strerror(errno)); - xfunlock(lockid); - return NULL; - } -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 20f4b79..cea850d 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -44,7 +44,9 @@ static struct option longopts[] = - { "help", 0, 0, 'h' }, - { "no-nfs-version", 1, 0, 'N' }, - { "nfs-version", 1, 0, 'V' }, -+ { "tcp", 0, 0, 't' }, - { "no-tcp", 0, 0, 'T' }, -+ { "udp", 0, 0, 'u' }, - { "no-udp", 0, 0, 'U' }, - { "port", 1, 0, 'P' }, - { "port", 1, 0, 'p' }, -@@ -67,8 +69,9 @@ main(int argc, char **argv) - int socket_up = 0; - unsigned int minorvers = 0; - unsigned int minorversset = 0; -+ unsigned int minormask = 0; - unsigned int versbits = NFSCTL_VERDEFAULT; -- unsigned int protobits = NFSCTL_ALLBITS; -+ unsigned int protobits = NFSCTL_PROTODEFAULT; - int grace = -1; - int lease = -1; - -@@ -104,10 +107,16 @@ main(int argc, char **argv) - else - NFSCTL_VERUNSET(versbits, i); - } -+ -+ nfssvc_get_minormask(&minormask); - /* We assume the kernel will default all minor versions to 'on', - * and allow the config file to disable some. - */ -- for (i = NFS4_MINMINOR; i <= NFS4_MAXMINOR; i++) { -+ if (NFSCTL_VERISSET(versbits, 4)) { -+ NFSCTL_MINORSET(minorversset, 0); -+ NFSCTL_MINORSET(minorvers, 0); -+ } -+ for (i = 1; i <= NFS4_MAXMINOR; i++) { - char tag[20]; - sprintf(tag, "vers4.%d", i); - /* The default for minor version support is to let the -@@ -119,12 +128,12 @@ main(int argc, char **argv) - * (i.e. don't set the bit in minorversset). - */ - if (!conf_get_bool("nfsd", tag, 1)) { -- NFSCTL_VERSET(minorversset, i); -- NFSCTL_VERUNSET(minorvers, i); -+ NFSCTL_MINORSET(minorversset, i); -+ NFSCTL_MINORUNSET(minorvers, i); - } - if (conf_get_bool("nfsd", tag, 0)) { -- NFSCTL_VERSET(minorversset, i); -- NFSCTL_VERSET(minorvers, i); -+ NFSCTL_MINORSET(minorversset, i); -+ NFSCTL_MINORSET(minorvers, i); - } - } - -@@ -138,7 +147,7 @@ main(int argc, char **argv) - } - } - -- while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTUrG:L:", longopts, NULL)) != EOF) { -+ while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTitUrG:L:", longopts, NULL)) != EOF) { - switch(c) { - case 'd': - xlog_config(D_ALL, 1); -@@ -179,13 +188,17 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) { -+ if (i < 0 || i > NFS4_MAXMINOR) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- NFSCTL_VERSET(minorversset, i); -- NFSCTL_VERUNSET(minorvers, i); -- break; -+ NFSCTL_MINORSET(minorversset, i); -+ NFSCTL_MINORUNSET(minorvers, i); -+ if (minorvers != 0) -+ break; -+ } else { -+ minorvers = 0; -+ minorversset = minormask; - } - case 3: - case 2: -@@ -201,14 +214,14 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) { -+ if (i < 0 || i > NFS4_MAXMINOR) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- NFSCTL_VERSET(minorversset, i); -- NFSCTL_VERSET(minorvers, i); -- break; -- } -+ NFSCTL_MINORSET(minorversset, i); -+ NFSCTL_MINORSET(minorvers, i); -+ } else -+ minorvers = minorversset = minormask; - case 3: - case 2: - NFSCTL_VERSET(versbits, c); -@@ -222,9 +235,15 @@ main(int argc, char **argv) - xlog_syslog(1); - xlog_stderr(0); - break; -+ case 't': -+ NFSCTL_TCPSET(protobits); -+ break; - case 'T': - NFSCTL_TCPUNSET(protobits); - break; -+ case 'u': -+ NFSCTL_UDPSET(protobits); -+ break; - case 'U': - NFSCTL_UDPUNSET(protobits); - break; -@@ -372,9 +391,9 @@ usage(const char *prog) - { - fprintf(stderr, "Usage:\n" - "%s [-d|--debug] [-H hostname] [-p|-P|--port port]\n" -- " [-N|--no-nfs-version version] [-V|--nfs-version version]\n" -- " [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] [-r|--rdma=]\n" -- " [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n", -+ " [-N|--no-nfs-version version] [-V|--nfs-version version]\n" -+ " [-s|--syslog] [-t|--tcp] [-T|--no-tcp] [-u|--udp] [-U|--no-udp]\n" -+ " [-r|--rdma=] [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n", - prog); - exit(2); - } -diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man -index 8901fb6..d83ef86 100644 ---- a/utils/nfsd/nfsd.man -+++ b/utils/nfsd/nfsd.man -@@ -57,7 +57,7 @@ This option can be used to request that - .B rpc.nfsd - does not offer certain versions of NFS. The current version of - .B rpc.nfsd --can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2. -+can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2. - .TP - .B \-s " or " \-\-syslog - By default, -@@ -67,22 +67,24 @@ logs error messages (and debug messages, if enabled) to stderr. This option make - log these messages to syslog instead. Note that errors encountered during - option processing will still be logged to stderr regardless of this option. - .TP -+.B \-t " or " \-\-tcp -+Instruct the kernel nfs server to open and listen on a TCP socket. This is the default. -+.TP - .B \-T " or " \-\-no-tcp --Disable --.B rpc.nfsd --from accepting TCP connections from clients. -+Instruct the kernel nfs server not to open and listen on a TCP socket. -+.TP -+.B \-u " or " \-\-udp -+Instruct the kernel nfs server to open and listen on a UDP socket. - .TP - .B \-U " or " \-\-no-udp --Disable --.B rpc.nfsd --from accepting UDP connections from clients. -+Instruct the kernel nfs server not to open and listen on a UDP socket. This is the default. - .TP - .B \-V " or " \-\-nfs-version vers - This option can be used to request that - .B rpc.nfsd - offer certain versions of NFS. The current version of - .B rpc.nfsd --can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2. -+can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2. - .TP - .B \-L " or " \-\-lease-time seconds - Set the lease-time used for NFSv4. This corresponds to how often -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 07f6ff1..e8609c1 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -330,36 +330,78 @@ nfssvc_set_time(const char *type, const int seconds) - } - - void -+nfssvc_get_minormask(unsigned int *mask) -+{ -+ int fd; -+ char *ptr = buf; -+ ssize_t size; -+ -+ fd = open(NFSD_VERS_FILE, O_RDONLY); -+ if (fd < 0) -+ return; -+ -+ size = read(fd, buf, sizeof(buf)); -+ if (size < 0) { -+ xlog(L_ERROR, "Getting versions failed: errno %d (%m)", errno); -+ goto out; -+ } -+ ptr[size] = '\0'; -+ for (;;) { -+ unsigned vers, minor = 0; -+ char *token = strtok(ptr, " "); -+ -+ if (!token) -+ break; -+ ptr = NULL; -+ if (*token != '+' && *token != '-') -+ continue; -+ if (sscanf(++token, "%u.%u", &vers, &minor) > 0 && -+ vers == 4 && minor <= NFS4_MAXMINOR) -+ NFSCTL_MINORSET(*mask, minor); -+ } -+out: -+ close(fd); -+ return; -+} -+ -+static int -+nfssvc_print_vers(char *ptr, unsigned size, unsigned vers, unsigned minorvers, -+ int isset) -+{ -+ char sign = isset ? '+' : '-'; -+ if (minorvers == 0) -+ return snprintf(ptr, size, "%c%u ", sign, vers); -+ return snprintf(ptr, size, "%c%u.%u ", sign, vers, minorvers); -+} -+ -+void - nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers, unsigned int minorversset) - { - int fd, n, off; -- char *ptr; - -- ptr = buf; - off = 0; - fd = open(NFSD_VERS_FILE, O_WRONLY); - if (fd < 0) - return; - -- for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { -- if (NFSCTL_VERISSET(minorversset, n)) { -- if (NFSCTL_VERISSET(minorvers, n)) -- off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); -- else -- off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); -- } -- } -- for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { -- if (NFSCTL_VERISSET(ctlbits, n)) -- off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); -- else -- off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n); -+ for (n = NFSD_MINVERS; n <= ((NFSD_MAXVERS < 3) ? NFSD_MAXVERS : 3); n++) -+ off += nfssvc_print_vers(&buf[off], sizeof(buf) - off, -+ n, 0, NFSCTL_VERISSET(ctlbits, n)); -+ -+ for (n = 0; n <= NFS4_MAXMINOR; n++) { -+ if (!NFSCTL_MINORISSET(minorversset, n)) -+ continue; -+ off += nfssvc_print_vers(&buf[off], sizeof(buf) - off, -+ 4, n, NFSCTL_MINORISSET(minorvers, n)); - } -+ if (!off--) -+ goto out; -+ buf[off] = '\0'; - xlog(D_GENERAL, "Writing version string to kernel: %s", buf); -- snprintf(ptr+off, sizeof(buf) - off, "\n"); -+ snprintf(&buf[off], sizeof(buf) - off, "\n"); - if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) - xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno); -- -+out: - close(fd); - - return; -diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h -index cd5a7e8..39ebf37 100644 ---- a/utils/nfsd/nfssvc.h -+++ b/utils/nfsd/nfssvc.h -@@ -28,3 +28,4 @@ void nfssvc_set_time(const char *type, const int seconds); - int nfssvc_set_rdmaport(const char *port); - void nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers4, unsigned int minorvers4set); - int nfssvc_threads(int nrservs); -+void nfssvc_get_minormask(unsigned int *mask); -diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am -index 152b680..ea32075 100644 ---- a/utils/statd/Makefile.am -+++ b/utils/statd/Makefile.am -@@ -18,6 +18,7 @@ statd_LDADD = ../../support/nsm/libnsm.a \ - $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - sm_notify_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ -+ ../../support/misc/libmisc.a \ - $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - - EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index 623213e..0c6766f 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -45,6 +45,8 @@ - - #define NLM_END_GRACE_FILE "/proc/fs/lockd/nlm_end_grace" - -+int lift_grace = 1; -+ - struct nsm_host { - struct nsm_host * next; - char * name; -@@ -494,6 +496,7 @@ main(int argc, char **argv) - opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60; - opt_srcport = conf_get_str("sm-notify", "outgoing-port"); - opt_srcaddr = conf_get_str("sm-notify", "outgoing-addr"); -+ lift_grace = conf_get_bool("sm-notify", "lift-grace", lift_grace); - s = conf_get_str("statd", "state-directory-path"); - if (s && !nsm_setup_pathnames(argv[0], s)) - exit(1); -@@ -570,7 +573,8 @@ usage: fprintf(stderr, - (void)nsm_retire_monitored_hosts(); - if (nsm_load_notify_list(smn_get_host) == 0) { - xlog(D_GENERAL, "No hosts to notify; exiting"); -- nsm_lift_grace_period(); -+ if (lift_grace) -+ nsm_lift_grace_period(); - return 0; - } - -diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man -index bb7f6e0..cfe1e4b 100644 ---- a/utils/statd/sm-notify.man -+++ b/utils/statd/sm-notify.man -@@ -241,6 +241,24 @@ These have the same effect as the command line options - .B v - respectively. - -+An additional value recognized in the -+.B [sm-notify] -+section is -+.BR lift-grace . -+By default, -+.B sm-notify -+will lift lockd's grace period early if it has no hosts to notify. -+Some high availability configurations will run one -+.B sm-notify -+per floating IP address. In these configurations, lifting the -+grace period early may prevent clients from reclaiming locks. -+.RB "Setting " lift-grace " to " n -+will prevent -+.B sm-notify -+from ending the grace period early. -+.B lift-grace -+has no corresponding command line option. -+ - The value recognized in the - .B [statd] - section is diff --git a/nfs-utils-2.1.2-rc3.patch b/nfs-utils-2.1.2-rc5.patch similarity index 73% rename from nfs-utils-2.1.2-rc3.patch rename to nfs-utils-2.1.2-rc5.patch index aec3cc4..81fdcd1 100644 --- a/nfs-utils-2.1.2-rc3.patch +++ b/nfs-utils-2.1.2-rc5.patch @@ -170,7 +170,7 @@ index 22cf539..d42eeef 100644 + free(paths->lockfn); +} diff --git a/support/include/conffile.h b/support/include/conffile.h -index 3fe3a78..20b1a32 100644 +index 3fe3a78..2d11a52 100644 --- a/support/include/conffile.h +++ b/support/include/conffile.h @@ -48,8 +48,6 @@ struct conf_list { @@ -182,12 +182,13 @@ index 3fe3a78..20b1a32 100644 extern int conf_begin(void); extern int conf_decode_base64(uint8_t *, uint32_t *, unsigned char *); extern int conf_end(int, int); -@@ -61,9 +59,8 @@ extern int conf_get_num(char *, char *, int); +@@ -61,9 +59,9 @@ extern int conf_get_num(char *, char *, int); extern _Bool conf_get_bool(char *, char *, _Bool); extern char *conf_get_str(char *, char *); extern char *conf_get_section(char *, char *, char *); -extern void conf_init(void); +extern void conf_init(const char *); ++extern void conf_cleanup(void); extern int conf_match_num(char *, char *, int); -extern void conf_reinit(void); extern int conf_remove(int, char *, char *); @@ -434,6 +435,30 @@ index 0000000..63597df + strcpy(base, parentdir); + return true; +} +diff --git a/support/misc/tcpwrapper.c b/support/misc/tcpwrapper.c +index 06b0a46..3128053 100644 +--- a/support/misc/tcpwrapper.c ++++ b/support/misc/tcpwrapper.c +@@ -72,6 +72,7 @@ present_address(const struct sockaddr *sap, char *buf, const size_t buflen) + case AF_INET: + if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0) + return; ++ break; + case AF_INET6: + if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, len) != 0) + return; +diff --git a/support/nfs/atomicio.c b/support/nfs/atomicio.c +index 5e760e6..aa819ca 100644 +--- a/support/nfs/atomicio.c ++++ b/support/nfs/atomicio.c +@@ -42,6 +42,7 @@ ssize_t atomicio(ssize_t(*f) (int, void *, size_t), int fd, void *_s, size_t n) + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; ++ /* FALLTHRU */ + case 0: + if (pos != 0) + return pos; diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c index e5e2579..9912afa 100644 --- a/support/nfs/cacheio.c @@ -466,7 +491,7 @@ index e5e2579..9912afa 100644 stb.st_mtime = time(0); diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index e717c1e..efbdc8b 100644 +index e717c1e..8690218 100644 --- a/support/nfs/conffile.c +++ b/support/nfs/conffile.c @@ -30,6 +30,10 @@ @@ -480,16 +505,20 @@ index e717c1e..efbdc8b 100644 #include #include #include -@@ -52,7 +56,7 @@ +@@ -52,9 +56,11 @@ #pragma GCC visibility push(hidden) static void conf_load_defaults(void); -static int conf_load(int trans, char *path); -+static int conf_load(int trans, const char *path); ++static char * conf_load(const char *path); static int conf_set(int , char *, char *, char *, char *, int , int ); ++static void conf_parse(int trans, char *buf, ++ char **section, char **subsection); -@@ -73,8 +77,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; + struct conf_trans { + TAILQ_ENTRY (conf_trans) link; +@@ -73,8 +79,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; /* * Radix-64 Encoding. */ @@ -500,7 +529,7 @@ index e717c1e..efbdc8b 100644 static const uint8_t asc2bin[] = { -@@ -105,7 +111,6 @@ struct conf_binding { +@@ -105,7 +113,6 @@ struct conf_binding { int is_default; }; @@ -508,7 +537,312 @@ index e717c1e..efbdc8b 100644 LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; static __inline__ uint8_t -@@ -369,20 +374,8 @@ conf_load_defaults(void) +@@ -199,7 +206,6 @@ conf_set_now(char *section, char *arg, char *tag, + node->tag = strdup(tag); + node->value = strdup(value); + node->is_default = is_default; +- + LIST_INSERT_HEAD(&conf_bindings[conf_hash (section)], node, link); + return 0; + } +@@ -209,17 +215,10 @@ conf_set_now(char *section, char *arg, char *tag, + * headers and feed tag-value pairs into our configuration database. + */ + static void +-conf_parse_line(int trans, char *line, size_t sz) ++conf_parse_line(int trans, char *line, int lineno, char **section, char **subsection) + { + char *val, *ptr; +- size_t i; +- size_t j; +- static char *section = 0; +- static char *arg = 0; +- static int ln = 0; + +- /* Lines starting with '#' or ';' are comments. */ +- ln++; + /* Ignore blank lines */ + if (*line == '\0') + return; +@@ -228,123 +227,188 @@ conf_parse_line(int trans, char *line, size_t sz) + while (isblank(*line)) + line++; + ++ /* Lines starting with '#' or ';' are comments. */ + if (*line == '#' || *line == ';') + return; + + /* '[section]' parsing... */ + if (*line == '[') { + line++; ++ ++ if (*section) { ++ free(*section); ++ *section = NULL; ++ } ++ if (*subsection) { ++ free(*subsection); ++ *subsection = NULL; ++ } ++ + /* Strip off any blanks after '[' */ + while (isblank(*line)) + line++; +- for (i = 0; i < sz; i++) { +- if (line[i] == ']') { +- break; +- } +- } +- if (section) +- free(section); +- if (i == sz) { ++ ++ /* find the closing ] */ ++ ptr = strchr(line, ']'); ++ if (ptr == NULL) { + xlog_warn("config file error: line %d: " +- "non-matched ']', ignoring until next section", ln); +- section = 0; ++ "non-matched ']', ignoring until next section", lineno); + return; + } ++ ++ /* just ignore everything after the closing ] */ ++ *(ptr--) = '\0'; ++ + /* Strip off any blanks before ']' */ +- val = line; +- j=0; +- while (*val && !isblank(*val)) +- val++, j++; +- if (*val) +- i = j; +- section = malloc(i+1); +- if (!section) { +- xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, +- (unsigned long)i); ++ while (ptr >= line && isblank(*ptr)) ++ *(ptr--)='\0'; ++ ++ /* look for an arg to split from the section name */ ++ val = strchr(line, '"'); ++ if (val != NULL) { ++ ptr = val - 1; ++ *(val++) = '\0'; ++ ++ /* trim away any whitespace before the " */ ++ while (ptr > line && isblank(*ptr)) ++ *(ptr--)='\0'; ++ } ++ ++ /* copy the section name */ ++ *section = strdup(line); ++ if (!*section) { ++ xlog_warn("conf_parse_line: %d: malloc failed", lineno); + return; + } +- strncpy(section, line, i); +- section[i] = '\0'; + +- if (arg) +- free(arg); +- arg = 0; ++ /* there is no arg, we are done */ ++ if (val == NULL) return; + ++ /* check for the closing " */ + ptr = strchr(val, '"'); +- if (ptr == NULL) +- return; +- line = ++ptr; +- while (*ptr && *ptr != '"' && *ptr != ']') +- ptr++; +- if (*ptr == '\0' || *ptr == ']') { ++ if (ptr == NULL) { + xlog_warn("config file error: line %d: " +- "non-matched '\"', ignoring until next section", ln); +- } else { +- *ptr = '\0'; +- arg = strdup(line); +- if (!arg) +- xlog_warn("conf_parse_line: %d: malloc arg failed", ln); ++ "non-matched '\"', ignoring until next section", lineno); ++ return; + } ++ *ptr = '\0'; ++ *subsection = strdup(val); ++ if (!*subsection) ++ xlog_warn("conf_parse_line: %d: malloc arg failed", lineno); + return; + } + + /* Deal with assignments. */ +- for (i = 0; i < sz; i++) { +- if (line[i] == '=') { +- /* If no section, we are ignoring the lines. */ +- if (!section) { ++ ptr = strchr(line, '='); ++ ++ /* not an assignment line */ ++ if (ptr == NULL) { ++ /* Other non-empty lines are weird. */ ++ if (line[strspn(line, " \t")]) + xlog_warn("config file error: line %d: " +- "ignoring line due to no section", ln); +- return; +- } +- line[strcspn (line, " \t=")] = '\0'; +- val = line + i + 1 + strspn (line + i + 1, " \t"); +- +- if (val[0] == '"') { +- val ++; +- j = strcspn(val, "\""); +- val[j] = 0; +- } else if (val[0] == '\'') { +- val ++; +- j = strcspn(val, "'"); +- val[j] = 0; +- } else { +- /* Skip trailing spaces and comments */ +- for (j = 0; val[j]; j++) { +- if ((val[j] == '#' || val[j] == ';') +- && (j == 0 || isspace(val[j-1]))) { +- val[j] = '\0'; +- break; +- } +- } +- while (j && isspace(val[j-1])) +- val[--j] = '\0'; +- } +- if (strcasecmp(line, "include") == 0) +- conf_load(trans, val); +- else +- /* XXX Perhaps should we not ignore errors? */ +- conf_set(trans, section, arg, line, val, 0, 0); ++ "line not empty and not an assignment", lineno); ++ return; ++ } ++ ++ /* If no section, we are ignoring the line. */ ++ if (!*section) { ++ xlog_warn("config file error: line %d: " ++ "ignoring line due to no section", lineno); ++ return; ++ } ++ ++ val = ptr + 1; ++ *(ptr--) = '\0'; ++ ++ /* strip spaces before and after the = */ ++ while (ptr >= line && isblank(*ptr)) ++ *(ptr--)='\0'; ++ while (*val != '\0' && isblank(*val)) ++ val++; ++ ++ if (*val == '"') { ++ val++; ++ ptr = strchr(val, '"'); ++ if (ptr == NULL) { ++ xlog_warn("config file error: line %d: " ++ "unmatched quotes", lineno); ++ return; ++ } ++ *ptr = '\0'; ++ } else ++ if (*val == '\'') { ++ val++; ++ ptr = strchr(val, '\''); ++ if (ptr == NULL) { ++ xlog_warn("config file error: line %d: " ++ "unmatched quotes", lineno); + return; + } ++ *ptr = '\0'; ++ } else { ++ /* Trim any trailing spaces and comments */ ++ if ((ptr=strchr(val, '#'))!=NULL) ++ *ptr = '\0'; ++ if ((ptr=strchr(val, ';'))!=NULL) ++ *ptr = '\0'; ++ ++ ptr = val + strlen(val) - 1; ++ while (ptr > val && isspace(*ptr)) ++ *(ptr--) = '\0'; + } +- /* Other non-empty lines are weird. */ +- i = strspn(line, " \t"); +- if (line[i]) +- xlog_warn("config file error: line %d:", ln); + +- return; ++ if (*line == '\0') { ++ xlog_warn("config file error: line %d: " ++ "missing tag in assignment", lineno); ++ return; ++ } ++ if (*val == '\0') { ++ xlog_warn("config file error: line %d: " ++ "missing value in assignment", lineno); ++ return; ++ } ++ ++ if (strcasecmp(line, "include")==0) { ++ /* load and parse subordinate config files */ ++ char * subconf = conf_load(val); ++ if (subconf == NULL) { ++ xlog_warn("config file error: line %d: " ++ "error loading included config", lineno); ++ return; ++ } ++ ++ /* copy the section data so the included file can inherit it ++ * without accidentally changing it for us */ ++ char * inc_section = NULL; ++ char * inc_subsection = NULL; ++ if (*section != NULL) { ++ inc_section = strdup(*section); ++ if (*subsection != NULL) ++ inc_subsection = strdup(*subsection); ++ } ++ ++ conf_parse(trans, subconf, &inc_section, &inc_subsection); ++ ++ if (inc_section) free(inc_section); ++ if (inc_subsection) free(inc_subsection); ++ free(subconf); ++ } else { ++ /* XXX Perhaps should we not ignore errors? */ ++ conf_set(trans, *section, *subsection, line, val, 0, 0); ++ } + } + + /* Parse the mapped configuration file. */ + static void +-conf_parse(int trans, char *buf, size_t sz) ++conf_parse(int trans, char *buf, char **section, char **subsection) + { + char *cp = buf; +- char *bufend = buf + sz; ++ char *bufend = NULL; + char *line; ++ int lineno = 0; + + line = cp; ++ bufend = buf + strlen(buf); + while (cp < bufend) { + if (*cp == '\n') { + /* Check for escaped newlines. */ +@@ -352,7 +416,8 @@ conf_parse(int trans, char *buf, size_t sz) + *(cp - 1) = *cp = ' '; + else { + *cp = '\0'; +- conf_parse_line(trans, line, cp - line); ++ lineno++; ++ conf_parse_line(trans, line, lineno, section, subsection); + line = cp + 1; + } + } +@@ -369,33 +434,21 @@ conf_load_defaults(void) return; } @@ -524,13 +858,66 @@ index e717c1e..efbdc8b 100644 - conf_reinit(); -} - - static int +-static int -conf_load(int trans, char *path) -+conf_load(int trans, const char *path) ++static char * ++conf_load(const char *path) { struct stat sb; if ((stat (path, &sb) == 0) || (errno != ENOENT)) { -@@ -421,15 +414,15 @@ conf_load(int trans, char *path) +- char *new_conf_addr; ++ char *new_conf_addr = NULL; + size_t sz = sb.st_size; + int fd = open (path, O_RDONLY, 0); + + if (fd == -1) { + xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", path); +- return -1; ++ return NULL; + } + +- new_conf_addr = malloc(sz); ++ new_conf_addr = malloc(sz+1); + if (!new_conf_addr) { + xlog_warn("conf_reinit: malloc (%lu) failed", (unsigned long)sz); + goto fail; +@@ -410,42 +463,103 @@ conf_load(int trans, char *path) + close(fd); + + /* XXX Should we not care about errors and rollback? */ +- conf_parse(trans, new_conf_addr, sz); +- free(new_conf_addr); +- return 0; ++ new_conf_addr[sz] = '\0'; ++ return new_conf_addr; + fail: + close(fd); +- free(new_conf_addr); ++ if (new_conf_addr) free(new_conf_addr); ++ } ++ return NULL; ++} ++ ++/* remove and free up any existing config state */ ++static void conf_free_bindings(void) ++{ ++ unsigned int i; ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { ++ struct conf_binding *cb, *next; ++ ++ cb = LIST_FIRST(&conf_bindings[i]); ++ for (; cb; cb = next) { ++ next = LIST_NEXT(cb, link); ++ LIST_REMOVE(cb, link); ++ free(cb->section); ++ free(cb->arg); ++ free(cb->tag); ++ free(cb->value); ++ free(cb); ++ } ++ LIST_INIT(&conf_bindings[i]); + } +- return -1; } /* Open the config file and map it into our address space, then parse it. */ @@ -539,17 +926,39 @@ index e717c1e..efbdc8b 100644 +static void +conf_reinit(const char *conf_file) { - struct conf_binding *cb = 0; +- struct conf_binding *cb = 0; int trans; - unsigned int i; +- unsigned int i; ++ char * conf_data; trans = conf_begin(); - if (conf_load(trans, conf_path) < 0) -+ if (conf_load(trans, conf_file) < 0) ++ conf_data = conf_load(conf_file); ++ ++ if (conf_data == NULL) return; /* Load default configuration values. */ -@@ -446,6 +439,20 @@ conf_reinit(void) + conf_load_defaults(); + ++ /* Parse config contents into the transaction queue */ ++ char *section = NULL; ++ char *subsection = NULL; ++ conf_parse(trans, conf_data, §ion, &subsection); ++ if (section) free(section); ++ if (subsection) free(subsection); ++ free(conf_data); ++ + /* Free potential existing configuration. */ +- for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { +- cb = LIST_FIRST (&conf_bindings[i]); +- for (; cb; cb = LIST_FIRST (&conf_bindings[i])) +- conf_remove_now(cb->section, cb->tag); +- } ++ conf_free_bindings(); + ++ /* Apply the new configuration values */ + conf_end(trans, 1); return; } @@ -566,11 +975,32 @@ index e717c1e..efbdc8b 100644 + if (conf_file == NULL) conf_file=NFS_CONFFILE; + conf_reinit(conf_file); +} ++ ++/* ++ * Empty the config and free up any used memory ++ */ ++void ++conf_cleanup(void) ++{ ++ conf_free_bindings(); ++ ++ struct conf_trans *node, *next; ++ for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { ++ next = TAILQ_NEXT(node, link); ++ TAILQ_REMOVE (&conf_trans_queue, node, link); ++ if (node->section) free(node->section); ++ if (node->arg) free(node->arg); ++ if (node->tag) free(node->tag); ++ if (node->value) free(node->value); ++ free (node); ++ } ++ TAILQ_INIT(&conf_trans_queue); ++} + /* * Return the numeric value denoted by TAG in section SECTION or DEF * if that tag does not exist. -@@ -533,7 +540,7 @@ retry: +@@ -533,7 +647,7 @@ retry: * or from environment */ char *env = getenv(cb->value+1); @@ -670,6 +1100,18 @@ index aafa755..52f5401 100644 } /** +diff --git a/support/nsm/rpc.c b/support/nsm/rpc.c +index 4e5f40e..0a8e56f 100644 +--- a/support/nsm/rpc.c ++++ b/support/nsm/rpc.c +@@ -38,6 +38,7 @@ + #include + #include + ++#include + #include + #include + #include diff --git a/systemd/Makefile.am b/systemd/Makefile.am index 0d15b9f..eef53c4 100644 --- a/systemd/Makefile.am @@ -919,6 +1361,50 @@ index 91c49a0..189b052 100644 .BR keytab-file , .BR cred-cache-directory , .BR preferred-realm . +diff --git a/systemd/nfs.systemd.man b/systemd/nfs.systemd.man +index 01801eb..46b476a 100644 +--- a/systemd/nfs.systemd.man ++++ b/systemd/nfs.systemd.man +@@ -79,7 +79,7 @@ unit should be enabled. + Several other units which might be considered to be optional, such as + .I rpc-gssd.service + are careful to only start if the required configuration file exists. +-.I rpc-gsdd.service ++.I rpc-gssd.service + will not start if the + .I krb5.keytab + file does not exist (typically in +@@ -120,10 +120,11 @@ be needed to reduce system load to an absolute minimum, or to reduce + attack surface by not running daemons that are not absolutely + required. + .PP +-Two particular services which this can apply to are +-.I rpcbind ++Three particular services which this can apply to are ++.IR rpcbind , ++.IR idmapd , + and +-.IR idmapd . ++.IR rpc-gssd . + .I rpcbind + is not part of the + .I nfs-utils +@@ -155,6 +156,15 @@ is not needed and not wanted, it can be masked with + .RS + .B systemctl mask idmapd + .RE ++.I rpc-gssd ++is assumed to be needed if the ++.I krb5.keytab ++file is present. If a site needs this file present but does not want ++.I rpc-gssd ++running, it can be masked with ++.RS ++.B systemctl mask rpc-gssd ++.RE + .SH FILES + /etc/nfs.conf + .br diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in index b353027..6807db3 100644 --- a/systemd/rpc-gssd.service.in @@ -1280,6 +1766,30 @@ index 0000000..25235ec +char *systemd_escape(char *path, char *suffix); + +#endif /* SYSTEMD_H */ +diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py +index 88ccdae..a68d702 100644 +--- a/tools/mountstats/mountstats.py ++++ b/tools/mountstats/mountstats.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/python + # -*- python-mode -*- + """Parse /proc/self/mountstats and display it in human readable form + """ +diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c +index 18b1622..68206cc 100644 +--- a/tools/rpcdebug/rpcdebug.c ++++ b/tools/rpcdebug/rpcdebug.c +@@ -74,7 +74,8 @@ main(int argc, char **argv) + opt_c = 1; + break; + case 'h': +- usage(0, module); ++ usage(0, module); /* usage does not return */ ++ break; + case 'm': + module = optarg; + break; diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man index 914b80f..4b3d3f0 100644 --- a/utils/blkmapd/blkmapd.man @@ -1311,10 +1821,18 @@ index 914b80f..4b3d3f0 100644 RFC 5661 for the NFS version 4.1 specification. .br diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index 8eb3fd0..c66669d 100644 +index 8eb3fd0..29bafb2 100644 --- a/utils/blkmapd/device-discovery.c +++ b/utils/blkmapd/device-discovery.c -@@ -50,21 +50,36 @@ +@@ -26,6 +26,7 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++#include + #include + #include + #include +@@ -50,21 +51,36 @@ #include #include @@ -1353,7 +1871,7 @@ index 8eb3fd0..c66669d 100644 struct bl_disk_path *bl_get_path(const char *filepath, struct bl_disk_path *paths) { -@@ -358,8 +373,8 @@ static void bl_rpcpipe_cb(void) +@@ -358,8 +374,8 @@ static void bl_rpcpipe_cb(void) continue; if (event->mask & IN_CREATE) { BL_LOG_WARNING("nfs pipe dir created\n"); @@ -1364,7 +1882,7 @@ index 8eb3fd0..c66669d 100644 } else if (event->mask & IN_DELETE) { BL_LOG_WARNING("nfs pipe dir deleted\n"); inotify_rm_watch(bl_watch_fd, nfs_pipedir_wfd); -@@ -372,7 +387,7 @@ static void bl_rpcpipe_cb(void) +@@ -372,7 +388,7 @@ static void bl_rpcpipe_cb(void) continue; if (event->mask & IN_CREATE) { BL_LOG_WARNING("blocklayout pipe file created\n"); @@ -1373,7 +1891,7 @@ index 8eb3fd0..c66669d 100644 if (bl_pipe_fd < 0) BL_LOG_ERR("open %s failed: %s\n", event->name, strerror(errno)); -@@ -437,6 +452,18 @@ int main(int argc, char **argv) +@@ -437,6 +453,18 @@ int main(int argc, char **argv) { int opt, dflag = 0, fg = 0, ret = 1; char pidbuf[64]; @@ -1392,7 +1910,7 @@ index 8eb3fd0..c66669d 100644 while ((opt = getopt(argc, argv, "hdf")) != -1) { switch (opt) { -@@ -496,12 +523,12 @@ int main(int argc, char **argv) +@@ -496,12 +524,12 @@ int main(int argc, char **argv) } /* open pipe file */ @@ -1409,6 +1927,26 @@ index 8eb3fd0..c66669d 100644 while (1) { /* discover device when needed */ +diff --git a/utils/blkmapd/device-inq.c b/utils/blkmapd/device-inq.c +index 0062a8f..c7952c3 100644 +--- a/utils/blkmapd/device-inq.c ++++ b/utils/blkmapd/device-inq.c +@@ -216,6 +216,7 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + if ((dev_id->len != 8) && (dev_id->len != 12) && + (dev_id->len != 16)) + break; ++ /* FALLTHRU */ + case 3: /* NAA */ + /* TODO: NAA validity judgement too complicated, + * so just ingore it here. +@@ -224,6 +225,7 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + BL_LOG_ERR("Binary code_set expected\n"); + break; + } ++ /* FALLTHRU */ + case 0: /* vendor specific */ + case 1: /* T10 vendor identification */ + current_id = dev_id->ids & 0xf; diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c index 61dddfb..beed1b3 100644 --- a/utils/exportfs/exportfs.c @@ -1858,7 +2396,7 @@ index d4ab894..5f34d2b 100644 .\".Sh SEE ALSO .\".Xr nylon.conf 4 diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c -index 0a4cc04..dc964c7 100644 +index 0a4cc04..e4b39ef 100644 --- a/utils/mount/configfile.c +++ b/utils/mount/configfile.c @@ -51,10 +51,6 @@ @@ -1872,6 +2410,15 @@ index 0a4cc04..dc964c7 100644 enum { MNT_NOARG=0, MNT_INTARG, +@@ -264,7 +260,7 @@ default_value(char *mopt) + } + } else if (strncasecmp(field, "vers", strlen("vers")) == 0) { + if ((options = po_split(field)) != NULL) { +- if (!nfs_nfs_version(options, &config_default_vers)) { ++ if (!nfs_nfs_version("nfs", options, &config_default_vers)) { + xlog_warn("Unable to set default version: %s", + strerror(errno)); + diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h index 69ffd1e..e4f8511 100644 --- a/utils/mount/mount_config.h @@ -1896,11 +2443,23 @@ index 69ffd1e..e4f8511 100644 } static inline char *mount_config_opts(char *spec, +diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c +index 1f01f7f..2d40657 100644 +--- a/utils/mount/mount_libmount.c ++++ b/utils/mount/mount_libmount.c +@@ -188,6 +188,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) + }; + + mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0); ++ mnt_context_disable_canonicalize(cxt, 1); + + while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) { + diff --git a/utils/mount/network.c b/utils/mount/network.c -index 7dceb2d..281e935 100644 +index 7dceb2d..8ab5be8 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c -@@ -33,6 +33,7 @@ +@@ -33,12 +33,19 @@ #include #include #include @@ -1908,7 +2467,28 @@ index 7dceb2d..281e935 100644 #include #include -@@ -804,6 +805,7 @@ int start_statd(void) + #include + #include +-#include ++#if defined(__GLIBC__) && (__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24) ++/* Cannot safely include linux/in6.h in old glibc, so hardcode the needed values */ ++# define IPV6_PREFER_SRC_PUBLIC 2 ++# define IPV6_ADDR_PREFERENCES 72 ++#else ++# include ++#endif + #include + #include + #include +@@ -93,7 +100,6 @@ static const char *nfs_version_opttbl[] = { + "v4", + "vers", + "nfsvers", +- "minorversion", + NULL, + }; + +@@ -804,6 +810,7 @@ int start_statd(void) pid_t pid = fork(); switch (pid) { case 0: /* child */ @@ -1916,7 +2496,110 @@ index 7dceb2d..281e935 100644 setgid(0); setuid(0); execle(START_STATD, START_STATD, NULL, envp); -@@ -1638,6 +1640,7 @@ int nfs_options2pmap(struct mount_options *options, +@@ -1233,6 +1240,7 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) + *program = tmp; + return 1; + } ++ /* FALLTHRU */ + case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'nfsprog=' option"), + progname); +@@ -1252,7 +1260,7 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) + * or FALSE if the option was specified with an invalid value. + */ + int +-nfs_nfs_version(struct mount_options *options, struct nfs_version *version) ++nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *version) + { + char *version_key, *version_val, *cptr; + int i, found = 0; +@@ -1267,10 +1275,11 @@ nfs_nfs_version(struct mount_options *options, struct nfs_version *version) + } + } + +- if (!found) ++ if (!found && strcmp(type, "nfs4") == 0) ++ version_val = type + 3; ++ else if (!found) + return 1; +- +- if (i <= 2 ) { ++ else if (i <= 2 ) { + /* v2, v3, v4 */ + version_val = version_key + 1; + version->v_mode = V_SPECIFIC; +@@ -1282,17 +1291,19 @@ nfs_nfs_version(struct mount_options *options, struct nfs_version *version) + if (!version_val) + goto ret_error; + +- if (!(version->major = strtol(version_val, &cptr, 10))) ++ version->major = strtol(version_val, &cptr, 10); ++ if (cptr == version_val || (*cptr && *cptr != '.')) + goto ret_error; +- +- if (strcmp(nfs_version_opttbl[i], "minorversion") == 0) { ++ if (version->major == 4 && *cptr != '.' && ++ (version_val = po_get(options, "minorversion")) != NULL) { ++ version->minor = strtol(version_val, &cptr, 10); ++ i = -1; ++ if (*cptr) ++ goto ret_error; + version->v_mode = V_SPECIFIC; +- version->minor = version->major; +- version->major = 4; + } else if (version->major < 4) + version->v_mode = V_SPECIFIC; +- +- if (*cptr == '.') { ++ else if (*cptr == '.') { + version_val = ++cptr; + if (!(version->minor = strtol(version_val, &cptr, 10)) && cptr == version_val) + goto ret_error; +@@ -1306,7 +1317,10 @@ nfs_nfs_version(struct mount_options *options, struct nfs_version *version) + return 1; + + ret_error: +- if (i <= 2 ) { ++ if (i < 0) { ++ nfs_error(_("%s: parsing error on 'minorversion=' option"), ++ progname); ++ } else if (i <= 2 ) { + nfs_error(_("%s: parsing error on 'v' option"), + progname); + } else if (i == 3 ) { +@@ -1381,6 +1395,7 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) + *port = tmp; + return 1; + } ++ /* FALLTHRU */ + case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'port=' option"), + progname); +@@ -1476,6 +1491,7 @@ nfs_mount_program(struct mount_options *options, unsigned long *program) + *program = tmp; + return 1; + } ++ /* FALLTHRU */ + case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountprog=' option"), + progname); +@@ -1507,6 +1523,7 @@ nfs_mount_version(struct mount_options *options, unsigned long *version) + *version = tmp; + return 1; + } ++ /* FALLTHRU */ + case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountvers=' option"), + progname); +@@ -1573,6 +1590,7 @@ nfs_mount_port(struct mount_options *options, unsigned long *port) + *port = tmp; + return 1; + } ++ /* FALLTHRU */ + case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountport=' option"), + progname); +@@ -1638,10 +1656,11 @@ int nfs_options2pmap(struct mount_options *options, struct pmap *nfs_pmap, struct pmap *mnt_pmap) { struct nfs_version version; @@ -1924,24 +2607,139 @@ index 7dceb2d..281e935 100644 if (!nfs_nfs_program(options, &nfs_pmap->pm_prog)) return 0; +- if (!nfs_nfs_version(options, &version)) ++ if (!nfs_nfs_version("nfs", options, &version)) + return 0; + if (version.v_mode == V_DEFAULT) + nfs_pmap->pm_vers = 0; +diff --git a/utils/mount/network.h b/utils/mount/network.h +index 9cc5dec..ecaac33 100644 +--- a/utils/mount/network.h ++++ b/utils/mount/network.h +@@ -72,7 +72,7 @@ struct nfs_version { + + int nfs_nfs_proto_family(struct mount_options *options, sa_family_t *family); + int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family); +-int nfs_nfs_version(struct mount_options *options, struct nfs_version *version); ++int nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *version); + int nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol); + + int nfs_options2pmap(struct mount_options *, +diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c +index 028e7cd..89629ed 100644 +--- a/utils/mount/nfs4mount.c ++++ b/utils/mount/nfs4mount.c +@@ -444,6 +444,7 @@ int nfs4mount(const char *spec, const char *node, int flags, + case RPC_SYSTEMERROR: + if (errno == ETIMEDOUT) + break; ++ /* FALLTHRU */ + default: + rpc_mount_errors(hostname, 0, bg); + goto fail; +diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c +index 930622d..ae4a3da 100644 +--- a/utils/mount/nfsmount.c ++++ b/utils/mount/nfsmount.c +@@ -683,6 +683,7 @@ nfsmount(const char *spec, const char *node, int flags, + case RPC_SYSTEMERROR: + if (errno == ETIMEDOUT) + break; ++ /* FALLTHRU */ + default: + rpc_mount_errors(*nfs_server.hostname, 0, bg); + goto fail; +diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c +index de284f2..e16fb6a 100644 +--- a/utils/mount/nfsumount.c ++++ b/utils/mount/nfsumount.c +@@ -180,7 +180,7 @@ static int nfs_umount_is_vers4(const struct mntentchn *mc) + options = po_split(pmc->m.mnt_opts); + if (options != NULL) { + struct nfs_version version; +- int rc = nfs_nfs_version(options, &version); ++ int rc = nfs_nfs_version("nfs", options, &version); + po_destroy(options); + if (rc && version.major == 4) + goto out_nfs4; diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 387d734..c0266e5 100644 +index 387d734..1d30d34 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c -@@ -315,9 +315,10 @@ static int nfs_set_version(struct nfsmount_info *mi) - if (!nfs_nfs_version(mi->options, &mi->version)) +@@ -73,6 +73,13 @@ + #define NFS_DEF_BG_TIMEOUT_MINUTES (10000u) + #endif + ++#ifndef NFS_DEFAULT_MAJOR ++#define NFS_DEFAULT_MAJOR 4 ++#endif ++#ifndef NFS_DEFAULT_MINOR ++#define NFS_DEFAULT_MINOR 2 ++#endif ++ + extern int nfs_mount_data_version; + extern char *progname; + extern int verbose; +@@ -80,8 +87,8 @@ extern int sloppy; + + struct nfsmount_info { + const char *spec, /* server:/path */ +- *node, /* mounted-on dir */ +- *type; /* "nfs" or "nfs4" */ ++ *node; /* mounted-on dir */ ++ char *type; /* "nfs" or "nfs4" */ + char *hostname; /* server's hostname */ + struct addrinfo *address; /* server's addresses */ + sa_family_t family; /* Address family */ +@@ -112,20 +119,28 @@ static void nfs_default_version(struct nfsmount_info *mi) + if (mi->version.v_mode == V_DEFAULT && + config_default_vers.v_mode != V_DEFAULT) { + mi->version.major = config_default_vers.major; +- mi->version.minor = config_default_vers.minor; ++ if (config_default_vers.v_mode == V_SPECIFIC) ++ mi->version.minor = config_default_vers.minor; ++ else ++ mi->version.minor = NFS_DEFAULT_MINOR; + return; + } + + if (mi->version.v_mode == V_GENERAL) { + if (config_default_vers.v_mode != V_DEFAULT && +- mi->version.major == config_default_vers.major) +- mi->version.minor = config_default_vers.minor; ++ mi->version.major == config_default_vers.major) { ++ if (config_default_vers.v_mode == V_SPECIFIC) ++ mi->version.minor = config_default_vers.minor; ++ else ++ mi->version.minor = NFS_DEFAULT_MINOR; ++ } else ++ mi->version.minor = NFS_DEFAULT_MINOR; + return; + } + + #endif /* MOUNT_CONFIG */ +- mi->version.major = 4; +- mi->version.minor = 2; ++ mi->version.major = NFS_DEFAULT_MAJOR; ++ mi->version.minor = NFS_DEFAULT_MINOR; + } + + /* +@@ -312,12 +327,9 @@ static int nfs_append_sloppy_option(struct mount_options *options) + + static int nfs_set_version(struct nfsmount_info *mi) + { +- if (!nfs_nfs_version(mi->options, &mi->version)) ++ if (!nfs_nfs_version(mi->type, mi->options, &mi->version)) return 0; - if (strncmp(mi->type, "nfs4", 4) == 0) -+ if (strncmp(mi->type, "nfs4", 4) == 0) { - mi->version.major = 4; +- mi->version.major = 4; - -+ mi->version.v_mode = V_GENERAL; -+ } /* * Before 2.6.32, the kernel NFS client didn't * support "-t nfs vers=4" mounts, so NFS version -@@ -517,6 +518,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4) +@@ -517,6 +529,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4) unsigned long protocol; struct pmap mnt_pmap; @@ -1952,7 +2750,49 @@ index 387d734..c0266e5 100644 /* * Version and transport negotiation is not required * and does not work for RDMA mounts. -@@ -834,9 +839,6 @@ check_result: +@@ -705,7 +721,7 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi, + { + struct mount_options *options = po_dup(mi->options); + int result = 0; +- char version_opt[16]; ++ char version_opt[32]; + char *extra_opts = NULL; + + if (!options) { +@@ -727,13 +743,25 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi, + } + + if (mi->version.v_mode != V_SPECIFIC) { +- if (mi->version.v_mode == V_GENERAL) +- snprintf(version_opt, sizeof(version_opt) - 1, +- "vers=%lu", mi->version.major); +- else +- snprintf(version_opt, sizeof(version_opt) - 1, +- "vers=%lu.%lu", mi->version.major, +- mi->version.minor); ++ char *fmt; ++ switch (mi->version.minor) { ++ /* Old kernels don't support the new "vers=x.y" ++ * option, but do support old versions of NFS4. ++ * So use the format that is most widely understood. ++ */ ++ case 0: ++ fmt = "vers=%lu"; ++ break; ++ case 1: ++ fmt = "vers=%lu,minorversion=%lu"; ++ break; ++ default: ++ fmt = "vers=%lu.%lu"; ++ break; ++ } ++ snprintf(version_opt, sizeof(version_opt) - 1, ++ fmt, mi->version.major, ++ mi->version.minor); + + if (po_append(options, version_opt) == PO_FAILED) { + errno = EINVAL; +@@ -834,9 +862,6 @@ check_result: case EINVAL: /* A less clear indication that our client * does not support NFSv4 minor version. */ @@ -1962,7 +2802,7 @@ index 387d734..c0266e5 100644 if (mi->version.v_mode != V_SPECIFIC) { if (mi->version.minor > 0) { mi->version.minor--; -@@ -858,19 +860,28 @@ check_result: +@@ -858,19 +883,28 @@ check_result: /* UDP-Only servers won't support v4, but maybe it * just isn't ready yet. So try v3, but double-check * with rpcbind for v4. */ @@ -1992,6 +2832,28 @@ index 387d734..c0266e5 100644 return nfs_try_mount_v3v2(mi, FALSE); } +@@ -1165,7 +1199,7 @@ static int nfsmount_start(struct nfsmount_info *mi) + * + * Returns a valid mount command exit code. + */ +-int nfsmount_string(const char *spec, const char *node, const char *type, ++int nfsmount_string(const char *spec, const char *node, char *type, + int flags, char **extra_opts, int fake, int child) + { + struct nfsmount_info mi = { +diff --git a/utils/mount/stropts.h b/utils/mount/stropts.h +index 37316eb..6acd2ac 100644 +--- a/utils/mount/stropts.h ++++ b/utils/mount/stropts.h +@@ -24,7 +24,7 @@ + #ifndef _NFS_UTILS_MOUNT_STROPTS_H + #define _NFS_UTILS_MOUNT_STROPTS_H + +-int nfsmount_string(const char *, const char *, const char *, int, ++int nfsmount_string(const char *, const char *, char *, int, + char **, int, int); + + #endif /* _NFS_UTILS_MOUNT_STROPTS_H */ diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c index d065830..8299256 100644 --- a/utils/mountd/auth.c @@ -2019,6 +2881,18 @@ index d065830..8299256 100644 close(fd); } else if (last_fd != -1 && stb.st_ino == last_inode) { /* We opened the etab file before, and its inode +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index ca6c84f..e49300d 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -11,6 +11,7 @@ + #include + #endif + ++#include + #include + #include + #include diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c index 61699e6..829f803 100644 --- a/utils/mountd/mountd.c @@ -2242,7 +3116,7 @@ index 527377f..3ae0dbb 100644 return NULL; } diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 20f4b79..111058f 100644 +index 20f4b79..f973203 100644 --- a/utils/nfsd/nfsd.c +++ b/utils/nfsd/nfsd.c @@ -34,8 +34,6 @@ @@ -2324,11 +3198,11 @@ index 20f4b79..111058f 100644 } - while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTUrG:L:", longopts, NULL)) != EOF) { -+ while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTitUrG:L:", longopts, NULL)) != EOF) { ++ while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTituUrG:L:", longopts, NULL)) != EOF) { switch(c) { case 'd': xlog_config(D_ALL, 1); -@@ -179,13 +186,17 @@ main(int argc, char **argv) +@@ -179,14 +186,19 @@ main(int argc, char **argv) case 4: if (*p == '.') { int i = atoi(p+1); @@ -2348,9 +3222,11 @@ index 20f4b79..111058f 100644 + minorvers = 0; + minorversset = minormask; } ++ /* FALLTHRU */ case 3: case 2: -@@ -201,14 +212,14 @@ main(int argc, char **argv) + NFSCTL_VERUNSET(versbits, c); +@@ -201,14 +213,15 @@ main(int argc, char **argv) case 4: if (*p == '.') { int i = atoi(p+1); @@ -2367,10 +3243,11 @@ index 20f4b79..111058f 100644 + NFSCTL_MINORSET(minorvers, i); + } else + minorvers = minorversset = minormask; ++ /* FALLTHRU */ case 3: case 2: NFSCTL_VERSET(versbits, c); -@@ -222,9 +233,15 @@ main(int argc, char **argv) +@@ -222,9 +235,15 @@ main(int argc, char **argv) xlog_syslog(1); xlog_stderr(0); break; @@ -2386,7 +3263,15 @@ index 20f4b79..111058f 100644 case 'U': NFSCTL_UDPUNSET(protobits); break; -@@ -372,9 +389,9 @@ usage(const char *prog) +@@ -244,6 +263,7 @@ main(int argc, char **argv) + break; + default: + fprintf(stderr, "Invalid argument: '%c'\n", c); ++ /* FALLTHRU */ + case 'h': + usage(progname); + } +@@ -372,9 +392,9 @@ usage(const char *prog) { fprintf(stderr, "Usage:\n" "%s [-d|--debug] [-H hostname] [-p|-P|--port port]\n" @@ -2554,7 +3439,7 @@ index cd5a7e8..39ebf37 100644 int nfssvc_threads(int nrservs); +void nfssvc_get_minormask(unsigned int *mask); diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c -index 7af9efb..124c923 100644 +index 7af9efb..0baaa3e 100644 --- a/utils/nfsdcltrack/nfsdcltrack.c +++ b/utils/nfsdcltrack/nfsdcltrack.c @@ -56,8 +56,6 @@ @@ -2575,6 +3460,14 @@ index 7af9efb..124c923 100644 xlog_from_conffile("nfsdcltrack"); val = conf_get_str("nfsdcltrack", "storagedir"); if (val) +@@ -581,6 +579,7 @@ main(int argc, char **argv) + switch (arg) { + case 'd': + xlog_config(D_ALL, 1); ++ break; + case 'f': + xlog_syslog(0); + xlog_stderr(1); diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c index 54cd748..1552eba 100644 --- a/utils/nfsdcltrack/sqlite.c diff --git a/nfs-utils.spec b/nfs-utils.spec index 2876f7b..4728d53 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 2.1.1 -Release: 6.rc4%{?dist}.1 +Release: 6.rc5%{?dist} Epoch: 1 # group all 32bit related archs @@ -15,8 +15,7 @@ Source3: nfs-utils_env.sh Source4: lockd.conf Source5: 24-nfs-server.conf -Patch001: nfs-utils-2.1.2-rc4.patch -Patch002: nfs-utils-2.1.1-rpc-include.patch +Patch001: nfs-utils-2.1.2-rc5.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -76,7 +75,6 @@ This package also contains the mount.nfs and umount.nfs program. %setup -q %patch001 -p1 -%patch002 -p1 %patch100 -p1 %patch101 -p1 @@ -290,6 +288,9 @@ fi /sbin/umount.nfs4 %changelog +* Thu Jul 27 2017 Steve Dickson 2.1.1-6.rc5 +- Updated to the latest RC releease: nfs-utils-2-1-2-rc5 + * Wed Jul 26 2017 Fedora Release Engineering - 1:2.1.1-6.rc4.1 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild