diff --git a/nfs-utils-1.2.3-sm-notify-res_init.patch b/nfs-utils-1.2.3-sm-notify-res_init.patch deleted file mode 100644 index 835e2f8..0000000 --- a/nfs-utils-1.2.3-sm-notify-res_init.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -up nfs-utils-2.1.1/utils/statd/sm-notify.c.orig nfs-utils-2.1.1/utils/statd/sm-notify.c ---- nfs-utils-2.1.1/utils/statd/sm-notify.c.orig 2017-04-26 12:46:56.511359133 -0400 -+++ nfs-utils-2.1.1/utils/statd/sm-notify.c 2017-04-26 12:47:18.155277994 -0400 -@@ -28,6 +28,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include "conffile.h" - #include "sockaddr.h" -@@ -91,6 +94,7 @@ smn_lookup(const char *name) - }; - int error; - -+ res_init(); - error = getaddrinfo(name, NULL, &hint, &ai); - if (error != 0) { - xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error)); diff --git a/nfs-utils-1.3.2-gssd-noclear-retval.patch b/nfs-utils-1.3.2-gssd-noclear-retval.patch deleted file mode 100644 index c19d730..0000000 --- a/nfs-utils-1.3.2-gssd-noclear-retval.patch +++ /dev/null @@ -1,27 +0,0 @@ -commit a705076172b274463563416adffe55f129740267 -Author: Steve Dickson -Date: Thu Jul 30 17:06:39 2015 -0400 - - rpc.gssd: Only clear the retval if it has not been set - - In gssd_search_krb5_keytab() an error code can be - cleared by blindly setting retval to zero. - - Reported-by: Jianhong Yin - Signed-off-by: Steve Dickson - -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index f1ebc0d..ecf17a2 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -772,7 +772,9 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - "keytab '%s'\n", k5err, kt_name); - } - -- retval = 0; -+ /* Only clear the retval if has not been set */ -+ if (retval < 0) -+ retval = 0; - out: - free(k5err); - return retval; diff --git a/nfs-utils-1.3.2-systemd-tmpfiles.patch b/nfs-utils-1.3.2-systemd-tmpfiles.patch deleted file mode 100644 index 5a17bea..0000000 --- a/nfs-utils-1.3.2-systemd-tmpfiles.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 68852818f732b31d3deb7cc76ef16f4e61c41aec Mon Sep 17 00:00:00 2001 -From: Colin Walters -Date: Sat, 9 May 2015 11:29:20 -0400 -Subject: [PATCH] systemd: Set var-lib-nfs-rpc_pipefs.mount After= tmpfiles - -OSTree is a mechanism for atomic updates of operating systems, with -designs for how system state is managed; in particular, `/var` should -start out empty, and components are responsible for creating content -there at runtime. - -rpm-ostree consumes RPMs and commits them to an OSTree repository. -It has some support for automatically synthesizing systemd `tmpfiles.d` -snippets from RPM content in `/var` using systemd-tmpfiles. - -However, in this case nfs-utils wants a mount point directory, and -it's running before systemd-tmpfiles. It should be perfectly fine to -do this mount after tmpfiles has run. - -A better fix for this would be to move transient directories to -`/run`; However, that would be an invasive change, which can happen -after this fix. - -Signed-off-by: Colin Walters ---- - systemd/var-lib-nfs-rpc_pipefs.mount | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/systemd/var-lib-nfs-rpc_pipefs.mount b/systemd/var-lib-nfs-rpc_pipefs.mount -index 33c5db6..26d1c76 100644 ---- a/systemd/var-lib-nfs-rpc_pipefs.mount -+++ b/systemd/var-lib-nfs-rpc_pipefs.mount -@@ -1,6 +1,7 @@ - [Unit] - Description=RPC Pipe File System - DefaultDependencies=no -+After=systemd-tmpfiles-setup.service - Conflicts=umount.target - - [Mount] --- -1.8.3.1 - diff --git a/nfs-utils-2.1.1-nfs-config.patch b/nfs-utils-2.1.1-nfs-config.patch deleted file mode 100644 index 2eb0fb1..0000000 --- a/nfs-utils-2.1.1-nfs-config.patch +++ /dev/null @@ -1,203 +0,0 @@ -diff -up nfs-utils-2.2.1/configure.ac.orig nfs-utils-2.2.1/configure.ac ---- nfs-utils-2.2.1/configure.ac.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/configure.ac 2017-10-25 15:52:43.287511759 -0400 -@@ -552,6 +552,11 @@ AC_SUBST([AM_CFLAGS], ["$my_am_cflags"]) - # Make sure that $ACLOCAL_FLAGS are used during a rebuild - AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \$(ACLOCAL_FLAGS)"]) - -+# make libexecdir available for substituion in config files -+# 2 "evals" needed late to expand variable names. -+AC_SUBST([_libexecdir]) -+AC_CONFIG_COMMANDS_PRE([eval eval _libexecdir=$libexecdir]) -+ - # make _sysconfdir available for substituion in config files - # 2 "evals" needed late to expand variable names. - AC_SUBST([_sysconfdir]) -@@ -559,6 +564,7 @@ AC_CONFIG_COMMANDS_PRE([eval eval _sysco - - AC_CONFIG_FILES([ - Makefile -+ systemd/nfs-config.service - systemd/rpc-gssd.service - linux-nfs/Makefile - support/Makefile -diff -up nfs-utils-2.2.1/systemd/Makefile.am.orig nfs-utils-2.2.1/systemd/Makefile.am ---- nfs-utils-2.2.1/systemd/Makefile.am.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/Makefile.am 2017-10-25 15:52:43.287511759 -0400 -@@ -6,6 +6,7 @@ unit_files = \ - nfs-client.target \ - rpc_pipefs.target \ - \ -+ nfs-config.service \ - nfs-mountd.service \ - nfs-server.service \ - nfs-utils.service \ -diff -up nfs-utils-2.2.1/systemd/nfs-blkmap.service.orig nfs-utils-2.2.1/systemd/nfs-blkmap.service ---- nfs-utils-2.2.1/systemd/nfs-blkmap.service.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/nfs-blkmap.service 2017-10-25 15:52:43.288511762 -0400 -@@ -10,7 +10,8 @@ PartOf=nfs-utils.service - [Service] - Type=forking - PIDFile=/var/run/blkmapd.pid --ExecStart=/usr/sbin/blkmapd -+EnvironmentFile=-/run/sysconfig/nfs-utils -+ExecStart=/usr/sbin/blkmapd $BLKMAPDARGS - - [Install] - WantedBy=nfs-client.target -diff -up nfs-utils-2.2.1/systemd/nfs-config.service.in.orig nfs-utils-2.2.1/systemd/nfs-config.service.in ---- nfs-utils-2.2.1/systemd/nfs-config.service.in.orig 2017-10-25 15:52:43.288511762 -0400 -+++ nfs-utils-2.2.1/systemd/nfs-config.service.in 2017-10-25 15:52:43.288511762 -0400 -@@ -0,0 +1,13 @@ -+[Unit] -+Description=Preprocess NFS configuration -+After=local-fs.target -+DefaultDependencies=no -+ -+[Service] -+Type=oneshot -+# This service needs to run any time any nfs service -+# is started, so changes to local config files get -+# incorporated. Having "RemainAfterExit=no" (the default) -+# ensures this happens. -+RemainAfterExit=no -+ExecStart=@_libexecdir@/nfs-utils/nfs-utils_env.sh -diff -up nfs-utils-2.2.1/systemd/nfs-idmapd.service.orig nfs-utils-2.2.1/systemd/nfs-idmapd.service ---- nfs-utils-2.2.1/systemd/nfs-idmapd.service.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/nfs-idmapd.service 2017-10-25 15:52:43.288511762 -0400 -@@ -6,6 +6,10 @@ After=rpc_pipefs.target local-fs.target - - BindsTo=nfs-server.service - -+Wants=nfs-config.service -+After=nfs-config.service -+ - [Service] -+EnvironmentFile=-/run/sysconfig/nfs-utils - Type=forking --ExecStart=/usr/sbin/rpc.idmapd -+ExecStart=/usr/sbin/rpc.idmapd $RPCIDMAPDARGS -diff -up nfs-utils-2.2.1/systemd/nfs-mountd.service.orig nfs-utils-2.2.1/systemd/nfs-mountd.service ---- nfs-utils-2.2.1/systemd/nfs-mountd.service.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/nfs-mountd.service 2017-10-25 15:52:43.289511766 -0400 -@@ -8,6 +8,10 @@ After=network-online.target local-fs.tar - After=rpcbind.socket - BindsTo=nfs-server.service - -+Wants=nfs-config.service -+After=nfs-config.service -+ - [Service] -+EnvironmentFile=-/run/sysconfig/nfs-utils - Type=forking --ExecStart=/usr/sbin/rpc.mountd -+ExecStart=/usr/sbin/rpc.mountd $RPCMOUNTDARGS -diff -up nfs-utils-2.2.1/systemd/nfs-server.service.orig nfs-utils-2.2.1/systemd/nfs-server.service ---- nfs-utils-2.2.1/systemd/nfs-server.service.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/nfs-server.service 2017-10-25 15:52:43.289511766 -0400 -@@ -16,11 +16,16 @@ Before= rpc-statd-notify.service - Wants=auth-rpcgss-module.service - After=rpc-gssd.service gssproxy.service rpc-svcgssd.service - -+Wants=nfs-config.service -+After=nfs-config.service -+ - [Service] -+EnvironmentFile=-/run/sysconfig/nfs-utils -+ - Type=oneshot - RemainAfterExit=yes - ExecStartPre=/usr/sbin/exportfs -r --ExecStart=/usr/sbin/rpc.nfsd -+ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS - ExecStop=/usr/sbin/rpc.nfsd 0 - ExecStopPost=/usr/sbin/exportfs -au - ExecStopPost=/usr/sbin/exportfs -f -diff -up nfs-utils-2.2.1/systemd/README.orig nfs-utils-2.2.1/systemd/README ---- nfs-utils-2.2.1/systemd/README.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/README 2017-10-25 15:52:43.289511766 -0400 -@@ -19,8 +19,8 @@ by a suitable 'preset' setting: - can work (if no type is given, ".service" is assumed). - - nfs-client.target -- If enabled, daemons needed for an nfs client are enabled. -- This does *not* include rpc.statd. The rpc-statd.service unit -+ If enabled, daemons needs for an nfs client are enabled. -+ This does *not* include rpc.statd. the rpc-statd.service unit - is started by /usr/sbin/start-statd which mount.nfs will run - if statd is needed. - -@@ -52,19 +52,11 @@ It cannot stop rpc.statd or rpc.gssd as - client and systemd cannot specify is two-pronged reverse dependency. - (i.e. stop this unit if none of these units are running) - --Distro specific configuration can be included in /etc/nfs.conf, or --by providing drop-in files which replace the ExecStart line for a given --service, and possibly add an EnvironmentFile line. -- --For example, if systemd/system/nfs-mountd.service.d/local.conf --contained -- [Service] -- EnvironmentFile=/etc/sysconfig/nfs -- ExecStart= -- ExecStart=/usr/sbin/rpc.mountd $RPCMOUNTDOPTS -- --then the setting of RPCMOUNTDOPTS in /etc/sysconfig/nfs would be --passed to rpc.mountd. -+Distro specific commandline configuration can be provided by -+installing a script /usr/libexec/nfs-utils/nfs-utils_env.sh -+This should write /run/sysconfig/nfs-utils based on configuration -+information such as in /etc/sysconfig/nfs or /etc/defaults/nfs. -+It is run once by nfs-config.service. - - rpc.gssd and rpc.svcgssd are assumed to be needed if /etc/krb5.keytab - is present. -diff -up nfs-utils-2.2.1/systemd/rpc-gssd.service.in.orig nfs-utils-2.2.1/systemd/rpc-gssd.service.in ---- nfs-utils-2.2.1/systemd/rpc-gssd.service.in.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/rpc-gssd.service.in 2017-10-25 15:52:43.290511769 -0400 -@@ -9,6 +9,11 @@ ConditionPathExists=@_sysconfdir@/krb5.k - - PartOf=nfs-utils.service - -+Wants=nfs-config.service -+After=nfs-config.service -+ - [Service] -+EnvironmentFile=-/run/sysconfig/nfs-utils -+ - Type=forking --ExecStart=/usr/sbin/rpc.gssd -+ExecStart=/usr/sbin/rpc.gssd $RPCGSSDARGS -diff -up nfs-utils-2.2.1/systemd/rpc-statd-notify.service.orig nfs-utils-2.2.1/systemd/rpc-statd-notify.service ---- nfs-utils-2.2.1/systemd/rpc-statd-notify.service.orig 2017-10-25 15:52:43.290511769 -0400 -+++ nfs-utils-2.2.1/systemd/rpc-statd-notify.service 2017-10-25 15:56:28.102284921 -0400 -@@ -10,7 +10,11 @@ After=nfs-server.service - - PartOf=nfs-utils.service - -+Wants=nfs-config.service -+After=nfs-config.service -+ - [Service] - Type=forking --ExecStart=-/usr/sbin/sm-notify -+EnvironmentFile=-/run/sysconfig/nfs-utils -+ExecStart=-/usr/sbin/sm-notify $SMNOTIFYARGS - RemainAfterExit=yes -diff -up nfs-utils-2.2.1/systemd/rpc-statd.service.orig nfs-utils-2.2.1/systemd/rpc-statd.service ---- nfs-utils-2.2.1/systemd/rpc-statd.service.orig 2017-10-25 15:32:19.000000000 -0400 -+++ nfs-utils-2.2.1/systemd/rpc-statd.service 2017-10-25 15:52:43.291511772 -0400 -@@ -8,8 +8,12 @@ After=network-online.target nss-lookup.t - - PartOf=nfs-utils.service - -+Wants=nfs-config.service -+After=nfs-config.service -+ - [Service] - Environment=RPC_STATD_NO_NOTIFY=1 -+EnvironmentFile=-/run/sysconfig/nfs-utils - Type=forking - PIDFile=/var/run/rpc.statd.pid --ExecStart=/usr/sbin/rpc.statd -+ExecStart=/usr/sbin/rpc.statd $STATDARGS diff --git a/nfs-utils-2.1.1-rpc-include.patch b/nfs-utils-2.1.1-rpc-include.patch deleted file mode 100644 index 5cf44f1..0000000 --- a/nfs-utils-2.1.1-rpc-include.patch +++ /dev/null @@ -1,20 +0,0 @@ -commit ba03a02c2fd912f370e1f55de921a403bf5f9247 -Author: Steve Dickson -Date: Thu Jun 22 12:56:41 2017 -0400 - - rpc.c: added include file so UINT16_MAX is defined. - - Signed-off-by: Steve Dickson - -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/nfs-utils-2.2.1-nfsidmap-abi.patch b/nfs-utils-2.2.1-nfsidmap-abi.patch deleted file mode 100644 index bdcfe52..0000000 --- a/nfs-utils-2.2.1-nfsidmap-abi.patch +++ /dev/null @@ -1,412 +0,0 @@ -commit 8d9bf479441d9d7a44a86b69026a7e9d431d3ade -Author: Justin Mitchell -Date: Tue Nov 7 09:28:25 2017 -0500 - - nfs-utils: Restore ABI compat with pre-merge libnfsidmap - - Prior to merge libnfsidmap leaked many private symbols that were - not defined in its API, creating an accidental ABI. - This patch renames and unhides symbols in order to match that ABI - until a cleaned up API can be established and released. - - Signed-off-by: Steve Dickson - -diff --git a/support/include/conffile.h b/support/include/conffile.h -index d4cb6b4..ad20067 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -60,7 +60,7 @@ extern _Bool conf_get_bool(const char *, const char *, _Bool); - extern char *conf_get_str(const char *, const char *); - extern char *conf_get_str_with_def(const char *, const char *, char *); - extern char *conf_get_section(const char *, const char *, const char *); --extern void conf_init(const char *); -+extern void conf_init_file(const char *); - extern void conf_cleanup(void); - extern int conf_match_num(const char *, const char *, int); - extern int conf_remove(int, const char *, const char *); -diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am -index c037c46..e573b69 100644 ---- a/support/nfs/Makefile.am -+++ b/support/nfs/Makefile.am -@@ -7,10 +7,10 @@ libnfs_la_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ - xcommon.c wildmat.c mydaemon.c \ - rpc_socket.c getport.c \ - svc_socket.c cacheio.c closeall.c nfs_mntent.c \ -- svc_create.c atomicio.c strlcpy.c strlcat.c -+ svc_create.c atomicio.c strlcat.c - libnfs_la_LIBADD = libnfsconf.la - --libnfsconf_la_SOURCES = conffile.c xlog.c -+libnfsconf_la_SOURCES = conffile.c xlog.c strlcpy.c - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 9c5ed8e..dce8148 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -53,11 +53,9 @@ - #include "conffile.h" - #include "xlog.h" - --#pragma GCC visibility push(hidden) -- - static void conf_load_defaults(void); --static char * conf_load(const char *path); --static int conf_set(int , const char *, const char *, const char *, -+static char * conf_readfile(const char *path); -+int conf_set(int , const char *, const char *, const char *, - const char *, int , int ); - static void conf_parse(int trans, char *buf, - char **section, char **subsection); -@@ -79,12 +77,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; - /* - * Radix-64 Encoding. - */ --#if 0 --static const uint8_t bin2asc[] -+const uint8_t bin2asc[] - = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; --#endif - --static const uint8_t asc2bin[] = -+const uint8_t asc2bin[] = - { - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, -@@ -370,7 +366,7 @@ conf_parse_line(int trans, char *line, int lineno, char **section, char **subsec - - if (strcasecmp(line, "include")==0) { - /* load and parse subordinate config files */ -- char * subconf = conf_load(val); -+ char * subconf = conf_readfile(val); - if (subconf == NULL) { - xlog_warn("config file error: line %d: " - "error loading included config", lineno); -@@ -435,7 +431,7 @@ conf_load_defaults(void) - } - - static char * --conf_load(const char *path) -+conf_readfile(const char *path) - { - struct stat sb; - if ((stat (path, &sb) == 0) || (errno != ENOENT)) { -@@ -444,19 +440,19 @@ conf_load(const char *path) - int fd = open (path, O_RDONLY, 0); - - if (fd == -1) { -- xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", path); -+ xlog_warn("conf_readfile: open (\"%s\", O_RDONLY) failed", path); - return NULL; - } - - new_conf_addr = malloc(sz+1); - if (!new_conf_addr) { -- xlog_warn("conf_reinit: malloc (%lu) failed", (unsigned long)sz); -+ xlog_warn("conf_readfile: malloc (%lu) failed", (unsigned long)sz); - goto fail; - } - - /* XXX I assume short reads won't happen here. */ - if (read (fd, new_conf_addr, sz) != (int)sz) { -- xlog_warn("conf_reinit: read (%d, %p, %lu) failed", -+ xlog_warn("conf_readfile: read (%d, %p, %lu) failed", - fd, new_conf_addr, (unsigned long)sz); - goto fail; - } -@@ -493,15 +489,19 @@ static void conf_free_bindings(void) - } - } - -+#pragma GCC visibility push(hidden) -+/* these are the real fuinctions, hidden from being exported -+ * by libnfsidmap ABI compatability */ -+ - /* Open the config file and map it into our address space, then parse it. */ - static void --conf_reinit(const char *conf_file) -+conf_load_file(const char *conf_file) - { - int trans; - char * conf_data; - - trans = conf_begin(); -- conf_data = conf_load(conf_file); -+ conf_data = conf_readfile(conf_file); - - if (conf_data == NULL) - return; -@@ -526,7 +526,7 @@ conf_reinit(const char *conf_file) - } - - void --conf_init (const char *conf_file) -+conf_init_file(const char *conf_file) - { - unsigned int i; - -@@ -536,7 +536,7 @@ conf_init (const char *conf_file) - TAILQ_INIT (&conf_trans_queue); - - if (conf_file == NULL) conf_file=NFS_CONFFILE; -- conf_reinit(conf_file); -+ conf_load_file(conf_file); - } - - /* -@@ -560,6 +560,8 @@ conf_cleanup(void) - TAILQ_INIT(&conf_trans_queue); - } - -+#pragma GCC visibility pop -+ - /* - * Return the numeric value denoted by TAG in section SECTION or DEF - * if that tag does not exist. -@@ -575,6 +577,7 @@ conf_get_num(const char *section, const char *tag, int def) - return def; - } - -+#pragma GCC visibility push(hidden) - /* - * Return the Boolean value denoted by TAG in section SECTION, or DEF - * if that tags does not exist. -@@ -606,6 +609,7 @@ conf_get_bool(const char *section, const char *tag, _Bool def) - return false; - return def; - } -+#pragma GCC visibility pop - - /* Validate X according to the range denoted by TAG in section SECTION. */ - int -@@ -651,6 +655,7 @@ conf_get_str_with_def(const char *section, const char *tag, char *def) - return result; - } - -+#pragma GCC visibility push(hidden) - /* - * Find a section that may or may not have an argument - */ -@@ -682,6 +687,7 @@ retry: - } - return 0; - } -+#pragma GCC visibility pop - - /* - * Build a list of string values out of the comma separated value denoted by -@@ -876,7 +882,7 @@ conf_trans_node(int transaction, enum conf_op op) - } - - /* Queue a set operation. */ --static int -+int - conf_set(int transaction, const char *section, const char *arg, - const char *tag, const char *value, int override, int is_default) - { -diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c -index 931387a..40011ee 100644 ---- a/support/nfsidmap/libnfsidmap.c -+++ b/support/nfsidmap/libnfsidmap.c -@@ -89,6 +89,10 @@ gid_t nobody_gid = (gid_t)-1; - #define NFS4DNSTXTREC "_nfsv4idmapdomain" - #endif - -+/* DEPRECATED these are for ABI compatibility only */ -+char * conf_path = PATH_IDMAPDCONF; -+void conf_reinit(void); -+void conf_init(void); - - /* Default logging fuction */ - static void default_logger(const char *fmt, ...) -@@ -342,7 +346,6 @@ int nfs4_init_name_mapping(char *conffile) - char *nobody_user, *nobody_group; - char *nostrip; - char *reformatgroup; -- char *conf_path; - - /* XXX: need to be able to reload configurations... */ - if (nfs4_plugins) /* already succesfully initialized */ -@@ -351,7 +354,7 @@ int nfs4_init_name_mapping(char *conffile) - conf_path = conffile; - else - conf_path = PATH_IDMAPDCONF; -- conf_init(conf_path); -+ conf_init_file(conf_path); - default_domain = conf_get_str("General", "Domain"); - if (default_domain == NULL) { - dflt = 1; -@@ -710,3 +713,13 @@ void nfs4_set_debug(int dbg_level, void (*logger)(const char *, ...)) - idmap_verbosity = dbg_level; - } - -+void conf_reinit(void) -+{ -+ conf_init_file(conf_path); -+} -+ -+void conf_init(void) -+{ -+ conf_init_file(conf_path); -+} -+ -diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c -index 59eee87..6e1d69c 100644 ---- a/systemd/rpc-pipefs-generator.c -+++ b/systemd/rpc-pipefs-generator.c -@@ -121,7 +121,7 @@ int main(int argc, char *argv[]) - exit(1); - } - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - s = conf_get_str("general", "pipefs-directory"); - if (!s) - exit(0); -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index 29bafb2..cae8c8d 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -456,7 +456,7 @@ int main(int argc, char **argv) - char *xrpcpipe_dir = NULL; - - strncpy(rpcpipe_dir, RPCPIPE_DIR, sizeof(rpcpipe_dir)); -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - CONF_SAVE(xrpcpipe_dir, conf_get_str("general", "pipefs-directory")); - if (xrpcpipe_dir != NULL) - strlcpy(rpcpipe_dir, xrpcpipe_dir, sizeof(rpcpipe_dir)); -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index beed1b3..448f195 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -107,7 +107,7 @@ main(int argc, char **argv) - xlog_stderr(1); - xlog_syslog(0); - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("exportfs"); - - /* NOTE: following uses "mountd" section of nfs.conf !!!! */ -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 053a223..2c14e5f 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -842,7 +842,7 @@ read_gss_conf(void) - { - char *s; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - use_memcache = conf_get_bool("gssd", "use-memcache", use_memcache); - root_uses_machine_creds = conf_get_bool("gssd", "use-machine-creds", - root_uses_machine_creds); -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 4cbe148..2b9ecea 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -252,7 +252,7 @@ main(int argc, char **argv) - warn("Skipping configuration file \"%s\"", conf_path); - conf_path = NULL; - } else { -- conf_init(conf_path); -+ conf_init_file(conf_path); - verbose = conf_get_num("General", "Verbosity", 0); - cache_entry_expiration = conf_get_num("General", - "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); -@@ -264,13 +264,13 @@ main(int argc, char **argv) - } - } else { - conf_path = NFS_CONFFILE; -- conf_init(conf_path); -+ conf_init_file(conf_path); - CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); - if (xpipefsdir != NULL) - strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); - - conf_path = _PATH_IDMAPDCONF; -- conf_init(conf_path); -+ conf_init_file(conf_path); - verbose = conf_get_num("General", "Verbosity", 0); - cache_entry_expiration = conf_get_num("General", - "cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY); -diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h -index e4f8511..7cc72fc 100644 ---- a/utils/mount/mount_config.h -+++ b/utils/mount/mount_config.h -@@ -32,7 +32,7 @@ static inline void mount_config_init(char *program) - /* - * Read the the default mount options - */ -- conf_init(MOUNTOPTS_CONFFILE); -+ conf_init_file(MOUNTOPTS_CONFFILE); - } - - static inline char *mount_config_opts(char *spec, -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 829f803..4c68702 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -679,7 +679,7 @@ main(int argc, char **argv) - else - progname = argv[0]; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("mountd"); - manage_gids = conf_get_bool("mountd", "manage-gids", manage_gids); - descriptors = conf_get_num("mountd", "descriptors", descriptors); -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index f973203..f41a2de 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -80,7 +80,7 @@ main(int argc, char **argv) - xlog_syslog(0); - xlog_stderr(1); - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("nfsd"); - count = conf_get_num("nfsd", "threads", count); - grace = conf_get_num("nfsd", "grace-time", grace); -diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c -index 7830cf4..76b06d2 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.c -+++ b/utils/nfsdcltrack/nfsdcltrack.c -@@ -564,7 +564,7 @@ main(int argc, char **argv) - xlog_syslog(1); - xlog_stderr(0); - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("nfsdcltrack"); - val = conf_get_str("nfsdcltrack", "storagedir"); - if (val) -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index d961dc0..6d19ec1 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -494,7 +494,7 @@ main(int argc, char **argv) - else - progname = argv[0]; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("sm-notify"); - opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60; - opt_srcport = conf_get_str("sm-notify", "outgoing-port"); -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 1443715..197d853 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -273,7 +273,7 @@ int main (int argc, char **argv) - /* Set hostname */ - MY_NAME = NULL; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("statd"); - out_port = conf_get_num("statd", "outgoing-port", out_port); - port = conf_get_num("statd", "port", port); diff --git a/nfs-utils-2.3.1-mount-auto-v3.patch b/nfs-utils-2.3.1-mount-auto-v3.patch deleted file mode 100644 index cddb48f..0000000 --- a/nfs-utils-2.3.1-mount-auto-v3.patch +++ /dev/null @@ -1,32 +0,0 @@ -commit 5f32083c759b468f5b0cb9302e4fe2848d37cc5b -Author: Steve Dickson -Date: Tue Apr 10 10:25:40 2018 -0400 - - mount.nfs: Fix auto protocol negotiation - - Commit 71b807e1 introduce a regression that - caused v3 not to be tried when v4 was not - supported by the server during auto negation. - - A check of the type in nfs_nfs_version() was - reverted back to only check for the "nfs4" - string not the "nfs" string which fixed the - problem. - - Signed-off-by: Steve Dickson - -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 9a2c878..e490399 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -1279,8 +1279,8 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v - } - } - -- if (!found && strncmp(type, "nfs", 3) == 0) -- version_val = "4"; -+ if (!found && strcmp(type, "nfs4") == 0) -+ version_val = type + 3; - else if (!found) - return 1; - else if (i <= 2 ) { diff --git a/nfs-utils-2.3.1-mount-setdefault-minor.patch b/nfs-utils-2.3.1-mount-setdefault-minor.patch deleted file mode 100644 index 2cfe61b..0000000 --- a/nfs-utils-2.3.1-mount-setdefault-minor.patch +++ /dev/null @@ -1,44 +0,0 @@ -commit 1a372a7b656ddf2be21ddad70b6c64c9d1d9d161 -Author: Steve Dickson -Date: Tue Apr 17 14:26:44 2018 -0400 - - nfsd: Set default minor versions - - Due to the way the kernel stores the supported - minor versions, when a minor is turned off, - via the -N flag, it can only turned back on - via -V flag. - - The default minor values should also enable - these minor versions. - - Acked-by: J. Bruce Fields - Signed-off-by: Steve Dickson - -diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h -index 7933ff5..b7d9e06 100644 ---- a/support/include/nfs/nfs.h -+++ b/support/include/nfs/nfs.h -@@ -40,6 +40,7 @@ struct nfs_fh_len { - #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) - - #define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ -+#define NFSCTL_MINDEFAULT (0x7) /* minor versions 4.1 and 4.2 */ - #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) - #define NFSCTL_MINORSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) - #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index f41a2de..2303a5d 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -65,8 +65,8 @@ main(int argc, char **argv) - int hcounter = 0; - struct conf_list *hosts; - int socket_up = 0; -- unsigned int minorvers = 0; -- unsigned int minorversset = 0; -+ unsigned int minorvers = NFSCTL_MINDEFAULT; -+ unsigned int minorversset = NFSCTL_MINDEFAULT; - unsigned int minormask = 0; - unsigned int versbits = NFSCTL_VERDEFAULT; - unsigned int protobits = NFSCTL_PROTODEFAULT; diff --git a/nfs-utils-2.3.2-gssd-revert.patch b/nfs-utils-2.3.2-gssd-revert.patch deleted file mode 100644 index aad43c1..0000000 --- a/nfs-utils-2.3.2-gssd-revert.patch +++ /dev/null @@ -1,43 +0,0 @@ -commit 5743891761f99bdfe6bf89956dab3a0e4c8a0fd0 -Author: Steve Dickson -Date: Wed Jun 27 12:42:05 2018 -0400 - - Revert "gssd.c: Remomved a couple of warning errors" - - This reverts commit 98118f5e382cdeb1acf25370768d5dfdc254ba5d. - Added back the 'm' character which cause memory to be - allocated for the string convertions. - - Signed-off-by: Steve Dickson - -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 7b21ee2..2c14e5f 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -279,16 +279,16 @@ gssd_read_service_info(int dirfd, struct clnt_info *clp) - * (commit bf19aacecbeebccb2c3d150a8bd9416b7dba81fe) - */ - numfields = fscanf(info, -- "RPC server: %s\n" -- "service: %s (%d) version %d\n" -- "address: %s\n" -- "protocol: %s\n" -- "port: %s\n", -- (char *)&server, -- (char *)&service, &program, &version, -- (char *)&address, -- (char *)&protoname, -- (char *)&port); -+ "RPC server: %ms\n" -+ "service: %ms (%d) version %d\n" -+ "address: %ms\n" -+ "protocol: %ms\n" -+ "port: %ms\n", -+ &server, -+ &service, &program, &version, -+ &address, -+ &protoname, -+ &port); - - - switch (numfields) { diff --git a/nfs-utils-2.3.3-nfsref-linking.patch b/nfs-utils-2.3.3-nfsref-linking.patch deleted file mode 100644 index ad8c6ba..0000000 --- a/nfs-utils-2.3.3-nfsref-linking.patch +++ /dev/null @@ -1,29 +0,0 @@ -commit 47aa0c9683e048eb325dc9779a5aff41250c2c68 -Author: Steve Dickson -Date: Tue Dec 11 12:51:37 2018 -0500 - - nfsref: switch the way libraries are linked. - - Link the static libs before the dynamic libs allowing - the routines in the static libs to be defined - by the dynamic libs - - Signed-off-by: Steve Dickson - -diff --git a/utils/nfsref/Makefile.am b/utils/nfsref/Makefile.am -index 44edc83..2409dd0 100644 ---- a/utils/nfsref/Makefile.am -+++ b/utils/nfsref/Makefile.am -@@ -27,9 +27,9 @@ noinst_HEADERS = nfsref.h - - sbin_PROGRAMS = nfsref - nfsref_SOURCES = add.c lookup.c nfsref.c remove.c --LDADD = $(LIBXML2) $(LIBCAP) \ -- ../../support/nfs/libnfs.la \ -- ../../support/junction/libjunction.la -+LDADD = ../../support/nfs/libnfs.la \ -+ ../../support/junction/libjunction.la \ -+ $(LIBXML2) $(LIBCAP) - - man8_MANS = nfsref.man - diff --git a/nfs-utils-2.3.3-printf-4k.patch b/nfs-utils-2.3.3-printf-4k.patch deleted file mode 100644 index f5db6f3..0000000 --- a/nfs-utils-2.3.3-printf-4k.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 94de9a2112cddfdacdb7d63b5c24be99e3db4124 -From: Steve Dickson -Date: Tue, 29 Jan 2019 15:31:06 -0500 -Subject: [PATCH] nfs-utils: Removed new error=format-overflow=2 errors - -With the latest C99-compliant gcc printf, sprintf, etc -now only support up to 4k in buffer sizes. There were -only a couple places that had to change to not -violated this new restriction - -Signed-off-by: Steve Dickson ---- - utils/blkmapd/device-discovery.c | 2 +- - utils/mount/error.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index 3a202e0..2ce60f8 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -239,7 +239,7 @@ int bl_discover_devices(void) - { - FILE *f; - int n; -- char buf[PATH_MAX], devname[PATH_MAX], fulldevname[PATH_MAX+NAME_MAX]; -+ char buf[PATH_MAX], devname[NAME_MAX], fulldevname[PATH_MAX]; - - /* release previous list */ - bl_release_disk(); -diff --git a/utils/mount/error.c b/utils/mount/error.c -index dfe5c7d..562f312 100644 ---- a/utils/mount/error.c -+++ b/utils/mount/error.c -@@ -50,8 +50,8 @@ - - extern char *progname; - --static char errbuf[BUFSIZ]; --static char *erreob = &errbuf[BUFSIZ]; -+static char errbuf[PATH_MAX]; -+static char *erreob = &errbuf[PATH_MAX]; - - /* Convert RPC errors into strings */ - static int rpc_strerror(int spos) --- -2.20.1 - diff --git a/nfs-utils-2.3.4-PRIx64-integers.patch b/nfs-utils-2.3.4-PRIx64-integers.patch deleted file mode 100644 index ad9c8db..0000000 --- a/nfs-utils-2.3.4-PRIx64-integers.patch +++ /dev/null @@ -1,118 +0,0 @@ -commit a8133e1fd174267536cd459e19cfe0a1cbbe037c -Author: Steve Dickson -Date: Wed May 22 13:55:37 2019 -0400 - - sqlite.c: Use PRIx64 macro to print 64-bit integers - - On 32 bit machines, using "%016lx" format throws out - an format error due to the -Werror=format=2 - compiler option. On 64 bit machines using that - format is correct. - - So use the PRIx64 macro to have the correct - format defined on the different machines. - - Signed-off-by: Steve Dickson - -diff --git a/utils/nfsdcld/sqlite.c b/utils/nfsdcld/sqlite.c -index faa62f9..cd658ef 100644 ---- a/utils/nfsdcld/sqlite.c -+++ b/utils/nfsdcld/sqlite.c -@@ -59,6 +59,7 @@ - #include - #include - #include -+#include - - #include "xlog.h" - #include "sqlite.h" -@@ -535,7 +536,7 @@ sqlite_copy_cltrack_records(int *num_rec) - xlog(L_ERROR, "Unable to begin transaction: %s", err); - goto rollback; - } -- ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%016lx\";", -+ ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%" PRIx64 "\";", - current_epoch); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -550,7 +551,7 @@ sqlite_copy_cltrack_records(int *num_rec) - xlog(L_ERROR, "Unable to clear records from current epoch: %s", err); - goto rollback; - } -- ret = snprintf(buf, sizeof(buf), "INSERT INTO \"rec-%016lx\" " -+ ret = snprintf(buf, sizeof(buf), "INSERT INTO \"rec-%" PRIx64 "\" " - "SELECT id FROM attached.clients;", - current_epoch); - if (ret < 0) { -@@ -703,7 +704,7 @@ sqlite_insert_client(const unsigned char *clname, const size_t namelen) - int ret; - sqlite3_stmt *stmt = NULL; - -- ret = snprintf(buf, sizeof(buf), "INSERT OR REPLACE INTO \"rec-%016lx\" " -+ ret = snprintf(buf, sizeof(buf), "INSERT OR REPLACE INTO \"rec-%" PRIx64 "\" " - "VALUES (?);", current_epoch); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -748,7 +749,7 @@ sqlite_remove_client(const unsigned char *clname, const size_t namelen) - int ret; - sqlite3_stmt *stmt = NULL; - -- ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%016lx\" " -+ ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%" PRIx64 "\" " - "WHERE id==?;", current_epoch); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -798,7 +799,7 @@ sqlite_check_client(const unsigned char *clname, const size_t namelen) - int ret; - sqlite3_stmt *stmt = NULL; - -- ret = snprintf(buf, sizeof(buf), "SELECT count(*) FROM \"rec-%016lx\" " -+ ret = snprintf(buf, sizeof(buf), "SELECT count(*) FROM \"rec-%" PRIx64 "\" " - "WHERE id==?;", recovery_epoch); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -873,7 +874,7 @@ sqlite_grace_start(void) - tcur++; - - ret = snprintf(buf, sizeof(buf), "UPDATE grace " -- "SET current = %ld, recovery = %ld;", -+ "SET current = %" PRId64 ", recovery = %" PRId64 ";", - (int64_t)tcur, (int64_t)trec); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -891,7 +892,7 @@ sqlite_grace_start(void) - goto rollback; - } - -- ret = snprintf(buf, sizeof(buf), "CREATE TABLE \"rec-%016lx\" " -+ ret = snprintf(buf, sizeof(buf), "CREATE TABLE \"rec-%" PRIx64 "\" " - "(id BLOB PRIMARY KEY);", - tcur); - if (ret < 0) { -@@ -915,7 +916,7 @@ sqlite_grace_start(void) - * values in the grace table, just clear out the records for - * the current reboot epoch. - */ -- ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%016lx\";", -+ ret = snprintf(buf, sizeof(buf), "DELETE FROM \"rec-%" PRIx64 "\";", - tcur); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -976,7 +977,7 @@ sqlite_grace_done(void) - goto rollback; - } - -- ret = snprintf(buf, sizeof(buf), "DROP TABLE \"rec-%016lx\";", -+ ret = snprintf(buf, sizeof(buf), "DROP TABLE \"rec-%" PRIx64 "\";", - recovery_epoch); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); -@@ -1027,7 +1028,7 @@ sqlite_iterate_recovery(int (*cb)(struct cld_client *clnt), struct cld_client *c - return -EINVAL; - } - -- ret = snprintf(buf, sizeof(buf), "SELECT * FROM \"rec-%016lx\";", -+ ret = snprintf(buf, sizeof(buf), "SELECT * FROM \"rec-%" PRIx64 "\";", - recovery_epoch); - if (ret < 0) { - xlog(L_ERROR, "sprintf failed!"); diff --git a/nfs-utils-2.3.4-mount-fallback.patch b/nfs-utils-2.3.4-mount-fallback.patch deleted file mode 100644 index 6c6e561..0000000 --- a/nfs-utils-2.3.4-mount-fallback.patch +++ /dev/null @@ -1,49 +0,0 @@ -commit a709f25c1da4a2fb44a1f3fd060298fbbd88aa3c -Author: Steve Dickson -Date: Tue May 14 15:52:50 2019 -0400 - - mount: Report correct error in the fall_back cases. - - In mount auto negotiation, a v3 mount is tried - when the v4 fails with error that could mean - v4 is not supported. - - When the v3 mount fails, the original v4 failure - should be used to set the errno, not the v3 failure. - - Fixes:https://bugzilla.redhat.com/show_bug.cgi?id=1709961 - Signed-off-by: Steve Dickson - -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 1bb7a73..901f995 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -889,7 +889,7 @@ out: - */ - static int nfs_autonegotiate(struct nfsmount_info *mi) - { -- int result; -+ int result, olderrno; - - result = nfs_try_mount_v4(mi); - check_result: -@@ -949,7 +949,18 @@ fall_back: - if (mi->version.v_mode == V_GENERAL) - /* v2,3 fallback not allowed */ - return result; -- return nfs_try_mount_v3v2(mi, FALSE); -+ -+ /* -+ * Save the original errno in case the v3 -+ * mount fails from one of the fall_back cases. -+ * Report the first failure not the v3 mount failure -+ */ -+ olderrno = errno; -+ if ((result = nfs_try_mount_v3v2(mi, FALSE))) -+ return result; -+ -+ errno = olderrno; -+ return result; - } - - /* diff --git a/nfs-utils-2.3.4-mountd-memleak.patch b/nfs-utils-2.3.4-mountd-memleak.patch deleted file mode 100644 index d52d063..0000000 --- a/nfs-utils-2.3.4-mountd-memleak.patch +++ /dev/null @@ -1,77 +0,0 @@ -commit 50ef80739d9e1e0df6616289ef2ff626a94666ee -Author: Steve Dickson -Date: Thu May 23 09:24:49 2019 -0400 - - rpc.mountd: Fix e_hostname and e_uuid leaks - - strdup of exportent uuid and hostname in getexportent() ends up leaking - memory. Free the memory before getexportent() is called again from xtab_read() - - Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1713360 - Signed-off-by: Nikhil Kshirsagar - Signed-off-by: Steve Dickson - -diff --git a/support/export/xtab.c b/support/export/xtab.c -index d42eeef..1e1d679 100644 ---- a/support/export/xtab.c -+++ b/support/export/xtab.c -@@ -50,6 +50,14 @@ xtab_read(char *xtab, char *lockfn, int is_export) - while ((xp = getexportent(is_export==0, 0)) != NULL) { - if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) && - !(exp = export_create(xp, is_export!=1))) { -+ if(xp->e_hostname) { -+ free(xp->e_hostname); -+ xp->e_hostname=NULL; -+ } -+ if(xp->e_uuid) { -+ free(xp->e_uuid); -+ xp->e_uuid=NULL; -+ } - continue; - } - switch (is_export) { -@@ -62,7 +70,16 @@ xtab_read(char *xtab, char *lockfn, int is_export) - if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0) - v4root_needed = 0; - break; -- } -+ } -+ if(xp->e_hostname) { -+ free(xp->e_hostname); -+ xp->e_hostname=NULL; -+ } -+ if(xp->e_uuid) { -+ free(xp->e_uuid); -+ xp->e_uuid=NULL; -+ } -+ - } - endexportent(); - xfunlock(lockid); -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index 5f4cb95..a7582ca 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -179,9 +179,20 @@ getexportent(int fromkernel, int fromexports) - } - ee.e_hostname = xstrdup(hostname); - -- if (parseopts(opt, &ee, fromexports && !has_default_subtree_opts, NULL) < 0) -- return NULL; -+ if (parseopts(opt, &ee, fromexports && !has_default_subtree_opts, NULL) < 0) { -+ if(ee.e_hostname) -+ { -+ xfree(ee.e_hostname); -+ ee.e_hostname=NULL; -+ } -+ if(ee.e_uuid) -+ { -+ xfree(ee.e_uuid); -+ ee.e_uuid=NULL; -+ } - -+ return NULL; -+ } - /* resolve symlinks */ - if (realpath(ee.e_path, rpath) != NULL) { - rpath[sizeof (rpath) - 1] = '\0'; diff --git a/nfs-utils-2.3.4-mountd-segfault.patch b/nfs-utils-2.3.4-mountd-segfault.patch deleted file mode 100644 index cbc6bd9..0000000 --- a/nfs-utils-2.3.4-mountd-segfault.patch +++ /dev/null @@ -1,83 +0,0 @@ -commit ca668e35d16ca296dee1bd000de8eb8d20433a21 -Author: Chuck Lever -Date: Tue May 28 10:02:49 2019 -0400 - - rpc.mountd: Fix mountd segfault - - After commit 8f459a072f93 ("Remove abuse of ai_canonname") the - ai_canonname field in addrinfo structs returned from - host_reliable_addrinfo() is always NULL. This results in mountd - segfaults when there are netgroups or hostname wildcards in - /etc/exports. - - Add an extra DNS query in check_wildcard() and check_netgroup() to - obtain the client's canonical hostname instead of dereferencing - the NULL pointer. - - Reported-by: Mark Wagner - Fixes: 8f459a072f93 ("Remove abuse of ai_canonname") - Signed-off-by: Chuck Lever - Signed-off-by: Steve Dickson - -diff --git a/support/export/client.c b/support/export/client.c -index a1fba01..ea4f89d 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -608,24 +608,36 @@ check_subnetwork(const nfs_client *clp, const struct addrinfo *ai) - static int - check_wildcard(const nfs_client *clp, const struct addrinfo *ai) - { -- char *cname = clp->m_hostname; -- char *hname = ai->ai_canonname; -+ char *hname, *cname = clp->m_hostname; - struct hostent *hp; - char **ap; -+ int match; - -- if (wildmat(hname, cname)) -- return 1; -+ match = 0; -+ -+ hname = host_canonname(ai->ai_addr); -+ if (hname == NULL) -+ goto out; -+ -+ if (wildmat(hname, cname)) { -+ match = 1; -+ goto out; -+ } - - /* See if hname aliases listed in /etc/hosts or nis[+] - * match the requested wildcard */ - hp = gethostbyname(hname); - if (hp != NULL) { - for (ap = hp->h_aliases; *ap; ap++) -- if (wildmat(*ap, cname)) -- return 1; -+ if (wildmat(*ap, cname)) { -+ match = 1; -+ goto out; -+ } - } - -- return 0; -+out: -+ free(hname); -+ return match; - } - - /* -@@ -645,11 +657,9 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - - match = 0; - -- hname = strdup(ai->ai_canonname); -- if (hname == NULL) { -- xlog(D_GENERAL, "%s: no memory for strdup", __func__); -+ hname = host_canonname(ai->ai_addr); -+ if (hname == NULL) - goto out; -- } - - /* First, try to match the hostname without - * splitting off the domain */ diff --git a/nfs-utils-2.5.1-nfsiostat-KeyError.patch b/nfs-utils-2.5.1-nfsiostat-KeyError.patch deleted file mode 100644 index a81d127..0000000 --- a/nfs-utils-2.5.1-nfsiostat-KeyError.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff -up nfs-utils-2.5.1/tools/mountstats/mountstats.py.orig nfs-utils-2.5.1/tools/mountstats/mountstats.py ---- nfs-utils-2.5.1/tools/mountstats/mountstats.py.orig 2020-09-08 10:59:58.289384682 -0400 -+++ nfs-utils-2.5.1/tools/mountstats/mountstats.py 2020-09-08 14:02:05.560514346 -0400 -@@ -951,10 +951,11 @@ def print_iostat_summary(old, new, devic - if not old or device not in old: - stats.display_iostats(time) - else: -- old_stats = DeviceData() -- old_stats.parse_stats(old[device]) -- diff_stats = stats.compare_iostats(old_stats) -- diff_stats.display_iostats(time) -+ if ("fstype autofs" not in str(old[device])) and ("fstype autofs" not in str(new[device])): -+ old_stats = DeviceData() -+ old_stats.parse_stats(old[device]) -+ diff_stats = stats.compare_iostats(old_stats) -+ diff_stats.display_iostats(time) - - def iostat_command(args): - """iostat-like command for NFS mount points -diff -up nfs-utils-2.5.1/tools/nfs-iostat/nfs-iostat.py.orig nfs-utils-2.5.1/tools/nfs-iostat/nfs-iostat.py ---- nfs-utils-2.5.1/tools/nfs-iostat/nfs-iostat.py.orig 2020-09-08 10:59:58.286384653 -0400 -+++ nfs-utils-2.5.1/tools/nfs-iostat/nfs-iostat.py 2020-09-08 14:02:05.560514346 -0400 -@@ -470,10 +470,13 @@ def parse_stats_file(filename): - def print_iostat_summary(old, new, devices, time, options): - stats = {} - diff_stats = {} -+ devicelist = [] - if old: - # Trim device list to only include intersection of old and new data, - # this addresses umounts due to autofs mountpoints -- devicelist = [x for x in old if x in devices] -+ for device in devices: -+ if "fstype autofs" not in str(old[device]): -+ devicelist.append(device) - else: - devicelist = devices - diff --git a/nfs-utils-2.5.1-rpcidmap-dontfreeconfig.patch b/nfs-utils-2.5.1-rpcidmap-dontfreeconfig.patch deleted file mode 100644 index de7241d..0000000 --- a/nfs-utils-2.5.1-rpcidmap-dontfreeconfig.patch +++ /dev/null @@ -1,29 +0,0 @@ -commit 086e6fdce887dd68e51b7bac4a2f21cea9a4fe01 -Author: Steve Dickson -Date: Fri Sep 4 14:15:53 2020 -0400 - - rpc.idmapd: Do not free config variables - - Commit 93e8f092e added a conf_cleanup() call to clean - up memory after the config file was parsed. It turns - out that memory still needed and it is not very much - so the call is removed. - - Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1873965 - - Signed-off-by: Steve Dickson - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index f3d2314..51c71fb 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -306,9 +306,6 @@ main(int argc, char **argv) - serverstart = 0; - } - -- /* Config memory is no longer needed */ -- conf_cleanup(); -- - while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) - switch (opt) { - case 'v': diff --git a/nfs-utils-2.5.2-rc4.patch b/nfs-utils-2.5.2-rc4.patch deleted file mode 100644 index 7ac28ba..0000000 --- a/nfs-utils-2.5.2-rc4.patch +++ /dev/null @@ -1,3020 +0,0 @@ -diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4 -index b5ac00f..e0b820b 100644 ---- a/aclocal/libevent.m4 -+++ b/aclocal/libevent.m4 -@@ -1,12 +1,12 @@ - dnl Checks for libevent - AC_DEFUN([AC_LIBEVENT], [ - -- dnl Check for libevent, but do not add -levent to LIBS -- AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent], -+ dnl Check for libevent, but do not add -levent_core to LIBS -+ AC_CHECK_LIB([event_core], [event_base_dispatch], [LIBEVENT=-levent_core], - [AC_MSG_ERROR([libevent not found.])]) - AC_SUBST(LIBEVENT) - -- AC_CHECK_HEADERS([event.h], , -+ AC_CHECK_HEADERS([event2/event.h], , - [AC_MSG_ERROR([libevent headers not found.])]) - - ])dnl -diff --git a/configure.ac b/configure.ac -index 942f3c0..dbb795f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -638,13 +638,12 @@ my_am_cflags="\ - -Werror=parentheses \ - -Werror=aggregate-return \ - -Werror=unused-result \ -- -Wno-cast-function-type \ - -fno-strict-aliasing \ - " - - AC_DEFUN([CHECK_CCSUPPORT], [ - my_save_cflags="$CFLAGS" -- CFLAGS=$1 -+ CFLAGS="-Werror $1" - AC_MSG_CHECKING([whether CC supports $1]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], - [AC_MSG_RESULT([yes])] -@@ -658,9 +657,10 @@ CHECK_CCSUPPORT([-Werror=format-overflow=2], [flg1]) - CHECK_CCSUPPORT([-Werror=int-conversion], [flg2]) - CHECK_CCSUPPORT([-Werror=incompatible-pointer-types], [flg3]) - CHECK_CCSUPPORT([-Werror=misleading-indentation], [flg4]) -+CHECK_CCSUPPORT([-Wno-cast-function-type], [flg5]) - AX_GCC_FUNC_ATTRIBUTE([format]) - --AC_SUBST([AM_CFLAGS], ["$my_am_cflags $flg1 $flg2 $flg3 $flg4"]) -+AC_SUBST([AM_CFLAGS], ["$my_am_cflags $flg1 $flg2 $flg3 $flg4 $flg5"]) - - # Make sure that $ACLOCAL_FLAGS are used during a rebuild - AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \$(ACLOCAL_FLAGS)"]) -diff --git a/support/include/xcommon.h b/support/include/xcommon.h -index 30b0403..efde83c 100644 ---- a/support/include/xcommon.h -+++ b/support/include/xcommon.h -@@ -7,7 +7,7 @@ - */ - - #ifndef _XMALLOC_H --#define _MALLOC_H -+#define _XMALLOC_H - - #ifdef HAVE_CONFIG_H - #include -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index 97eb318..037febd 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -838,6 +838,7 @@ struct export_features *get_export_features(void) - close(fd); - if (c == -1) - goto err; -+ buf[c] = 0; - c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags); - if (c != 2) - goto err; -diff --git a/support/nfs/xlog.c b/support/nfs/xlog.c -index 687d862..86acd6a 100644 ---- a/support/nfs/xlog.c -+++ b/support/nfs/xlog.c -@@ -156,13 +156,29 @@ xlog_enabled(int fac) - void - xlog_backend(int kind, const char *fmt, va_list args) - { -- va_list args2; -- - if (!(kind & (L_ALL)) && !(logging && (kind & logmask))) - return; - -- if (log_stderr) -+ if (log_stderr) { -+ va_list args2; -+#ifdef VERBOSE_PRINTF -+ time_t now; -+ struct tm *tm; -+ -+ time(&now); -+ tm = localtime(&now); -+ fprintf(stderr, "%s[%d] %04d-%02d-%02d %02d:%02d:%02d ", -+ log_name, log_pid, -+ tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec); -+#else -+ fprintf(stderr, "%s: ", log_name); -+#endif - va_copy(args2, args); -+ vfprintf(stderr, fmt, args2); -+ fprintf(stderr, "\n"); -+ va_end(args2); -+ } - - if (log_syslog) { - switch (kind) { -@@ -185,25 +201,6 @@ xlog_backend(int kind, const char *fmt, va_list args) - } - } - -- if (log_stderr) { --#ifdef VERBOSE_PRINTF -- time_t now; -- struct tm *tm; -- -- time(&now); -- tm = localtime(&now); -- fprintf(stderr, "%s[%d] %04d-%02d-%02d %02d:%02d:%02d ", -- log_name, log_pid, -- tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, -- tm->tm_hour, tm->tm_min, tm->tm_sec); --#else -- fprintf(stderr, "%s: ", log_name); --#endif -- vfprintf(stderr, fmt, args2); -- fprintf(stderr, "\n"); -- va_end(args2); -- } -- - if (kind == L_FATAL) - exit(1); - } -diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c -index bce448c..0a912e5 100644 ---- a/support/nfsidmap/libnfsidmap.c -+++ b/support/nfsidmap/libnfsidmap.c -@@ -237,24 +237,40 @@ static int load_translation_plugin(char *method, struct mapping_plugin *plgn) - { - void *dl = NULL; - struct trans_func *trans = NULL; -- libnfsidmap_plugin_init_t init_func; -+ libnfsidmap_plugin_init_t init_func = NULL; - char plgname[128]; - int ret = 0; - -- snprintf(plgname, sizeof(plgname), "%s/%s.so", PATH_PLUGINS, method); -+ /* Look for library using search path first to allow overriding */ -+ snprintf(plgname, sizeof(plgname), "%s.so", method); - - dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL); -- if (dl == NULL) { -- IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s", -- dlerror())); -- return -1; -+ if (dl != NULL) { -+ /* Is it really one of our libraries */ -+ init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC); -+ if (init_func == NULL) { -+ dlclose(dl); -+ dl = NULL; -+ } - } -- init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC); -- if (init_func == NULL) { -- IDMAP_LOG(1, ("libnfsidmap: Unable to get init function: %s", -- dlerror())); -- dlclose(dl); -- return -1; -+ -+ if (dl == NULL) { -+ /* Fallback to hard-coded path */ -+ snprintf(plgname, sizeof(plgname), "%s/%s.so", PATH_PLUGINS, method); -+ -+ dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL); -+ if (dl == NULL) { -+ IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s: %s", -+ plgname, dlerror())); -+ return -1; -+ } -+ init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC); -+ if (init_func == NULL) { -+ IDMAP_LOG(1, ("libnfsidmap: Unable to get init function: %s: %s", -+ plgname, dlerror())); -+ dlclose(dl); -+ return -1; -+ } - } - trans = init_func(); - if (trans == NULL) { -@@ -496,6 +512,19 @@ out: - return ret ? -ENOENT: 0; - } - -+void nfs4_term_name_mapping(void) -+{ -+ if (nfs4_plugins) -+ unload_plugins(nfs4_plugins); -+ if (gss_plugins) -+ unload_plugins(gss_plugins); -+ -+ nfs4_plugins = gss_plugins = NULL; -+ -+ free_local_realms(); -+ conf_cleanup(); -+} -+ - int - nfs4_get_default_domain(char *UNUSED(server), char *domain, size_t len) - { -diff --git a/support/nfsidmap/nfsidmap.h b/support/nfsidmap/nfsidmap.h -index 1063065..5a79568 100644 ---- a/support/nfsidmap/nfsidmap.h -+++ b/support/nfsidmap/nfsidmap.h -@@ -50,6 +50,7 @@ typedef struct _extra_mapping_params { - typedef void (*nfs4_idmap_log_function_t)(const char *, ...); - - int nfs4_init_name_mapping(char *conffile); -+void nfs4_term_name_mapping(void); - int nfs4_get_default_domain(char *server, char *domain, size_t len); - int nfs4_uid_to_name(uid_t uid, char *domain, char *name, size_t len); - int nfs4_gid_to_name(gid_t gid, char *domain, char *name, size_t len); -diff --git a/support/nfsidmap/nfsidmap_common.c b/support/nfsidmap/nfsidmap_common.c -index f89b82e..4d2cb14 100644 ---- a/support/nfsidmap/nfsidmap_common.c -+++ b/support/nfsidmap/nfsidmap_common.c -@@ -34,12 +34,21 @@ static char * toupper_str(char *s) - return s; - } - -+static struct conf_list *local_realms = NULL; -+ -+void free_local_realms(void) -+{ -+ if (local_realms) { -+ conf_free_list(local_realms); -+ local_realms = NULL; -+ } -+} -+ - /* Get list of "local equivalent" realms. Meaning the list of realms - * where john@REALM.A is considered the same user as john@REALM.B - * If not specified, default to upper-case of local domain name */ - struct conf_list *get_local_realms(void) - { -- static struct conf_list *local_realms = NULL; - if (local_realms) return local_realms; - - local_realms = conf_get_list("General", "Local-Realms"); -diff --git a/support/nfsidmap/nfsidmap_private.h b/support/nfsidmap/nfsidmap_private.h -index f1af55f..a5cb6dd 100644 ---- a/support/nfsidmap/nfsidmap_private.h -+++ b/support/nfsidmap/nfsidmap_private.h -@@ -37,6 +37,7 @@ - #include "conffile.h" - - struct conf_list *get_local_realms(void); -+void free_local_realms(void); - int get_nostrip(void); - int get_reformat_group(void); - -diff --git a/support/nfsidmap/nss.c b/support/nfsidmap/nss.c -index 9d46499..669760b 100644 ---- a/support/nfsidmap/nss.c -+++ b/support/nfsidmap/nss.c -@@ -467,6 +467,17 @@ static int nss_plugin_init(void) - return 0; - } - -+/* -+ * Called by dlclose(). See dlopen(3) man page -+ */ -+__attribute__((destructor)) -+static int nss_plugin_term(void) -+{ -+ free_local_realms(); -+ conf_cleanup(); -+ return 0; -+} -+ - - struct trans_func nss_trans = { - .name = "nsswitch", -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 24118d6..06c1adb 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -1,18 +1,18 @@ - [Unit] - Description=NFS server and services - DefaultDependencies=no --Requires= network.target proc-fs-nfsd.mount --Requires= nfs-mountd.service -+Requires=network.target proc-fs-nfsd.mount -+Requires=nfs-mountd.service - Wants=rpcbind.socket network-online.target - Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service - Wants=nfsdcld.service - --After= network-online.target local-fs.target --After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service --After= nfs-idmapd.service rpc-statd.service --After= nfsdcld.service --Before= rpc-statd-notify.service -+After=network-online.target local-fs.target -+After=proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service -+After=nfs-idmapd.service rpc-statd.service -+After=nfsdcld.service -+Before=rpc-statd-notify.service - - # GSS services dependencies and ordering - Wants=auth-rpcgss-module.service -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 014f38a..00adc96 100755 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # -*- python-mode -*- - """Parse /proc/self/mountstats and display it in human readable form - """ -@@ -560,7 +560,10 @@ class DeviceData: - # the reference to them. so we build new lists here - # for the result object. - for op in result.__rpc_data['ops']: -- result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) -+ try: -+ result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) -+ except KeyError: -+ continue - - # update the remaining keys - if protocol == 'udp': -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index b7e98a2..4f5e8a6 100755 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # -*- python-mode -*- - """Emulate iostat for NFS mount points using /proc/self/mountstats - """ -@@ -213,8 +213,11 @@ class DeviceData: - # the reference to them. so we build new lists here - # for the result object. - for op in result.__rpc_data['ops']: -- result.__rpc_data[op] = list(map( -- difference, self.__rpc_data[op], old_stats.__rpc_data[op])) -+ try: -+ result.__rpc_data[op] = list(map( -+ difference, self.__rpc_data[op], old_stats.__rpc_data[op])) -+ except KeyError: -+ continue - - # update the remaining keys we care about - result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -@@ -380,6 +383,8 @@ class DeviceData: - sends = float(self.__rpc_data['rpcsends']) - if sample_time == 0: - sample_time = float(self.__nfs_data['age']) -+ if sample_time == 0: -+ sample_time = 1; - return (sends / sample_time) - - def display_iostats(self, sample_time, which): -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index a04a789..cde5e51 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -85,8 +85,11 @@ grab_lockfile() - static void - release_lockfile() - { -- if (_lockfd != -1) -+ if (_lockfd != -1) { - lockf(_lockfd, F_ULOCK, 0); -+ close(_lockfd); -+ _lockfd = -1; -+ } - } - - int -@@ -184,6 +187,7 @@ main(int argc, char **argv) - xtab_export_read(); - dump(f_verbose, f_export_format); - free_state_path_names(&etab); -+ export_freeall(); - return 0; - } - } -@@ -225,6 +229,7 @@ main(int argc, char **argv) - xtab_export_write(); - cache_flush(force_flush); - free_state_path_names(&etab); -+ export_freeall(); - - return export_errno; - } -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index 321046b..21d3bb8 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -67,7 +67,6 @@ gssd_CFLAGS = \ - svcgssd_SOURCES = \ - $(COMMON_SRCS) \ - svcgssd.c \ -- svcgssd_main_loop.c \ - svcgssd_mech2file.c \ - svcgssd_proc.c \ - svcgssd_krb5.c \ -@@ -78,6 +77,7 @@ svcgssd_SOURCES = \ - svcgssd_LDADD = \ - ../../support/nfs/libnfs.la \ - ../../support/nfsidmap/libnfsidmap.la \ -+ $(LIBEVENT) \ - $(RPCSECGSS_LIBS) \ - $(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC) - -diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c -index 2a7f3a1..982b96f 100644 ---- a/utils/gssd/gss_names.c -+++ b/utils/gssd/gss_names.c -@@ -110,10 +110,12 @@ get_hostbased_client_name(gss_name_t client_name, gss_OID mech, - /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to - * an NT_HOSTBASED_SERVICE name */ - if (g_OID_equal(&krb5oid, mech)) { -- if (get_krb5_hostbased_name(&name, &cname) == 0) -- *hostbased_name = cname; -+ if (get_krb5_hostbased_name(&name, &cname) != 0) -+ goto out_rel_buf; -+ *hostbased_name = cname; - } else { - printerr(1, "WARNING: unknown/unsupport mech OID\n"); -+ goto out_rel_buf; - } - - res = 0; -diff --git a/utils/gssd/gss_util.c b/utils/gssd/gss_util.c -index 2e6d40f..a4b2777 100644 ---- a/utils/gssd/gss_util.c -+++ b/utils/gssd/gss_util.c -@@ -339,3 +339,9 @@ out: - return retval; - } - -+void -+gssd_cleanup(void) -+{ -+ u_int32_t min_stat; -+ gss_release_cred(&min_stat, &gssd_creds); -+} -diff --git a/utils/gssd/gss_util.h b/utils/gssd/gss_util.h -index aa9f778..4da64e3 100644 ---- a/utils/gssd/gss_util.h -+++ b/utils/gssd/gss_util.h -@@ -41,6 +41,7 @@ int gssd_acquire_cred(char *server_name, const gss_OID oid); - void pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat, - const gss_OID mech); - int gssd_check_mechs(void); -+void gssd_cleanup(void); - - #ifndef HAVE_LIBGSSGLUE - #include -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 588da0f..85bc4b0 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -64,7 +64,7 @@ - #include - #include - #include --#include -+#include - - #include "gssd.h" - #include "err_util.h" -@@ -77,7 +77,7 @@ static char *pipefs_path = GSSD_PIPEFS_DIR; - static DIR *pipefs_dir; - static int pipefs_fd; - static int inotify_fd; --struct event inotify_ev; -+struct event *inotify_ev; - - char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; - char **ccachesearch; -@@ -90,9 +90,9 @@ char *ccachedir = NULL; - /* Avoid DNS reverse lookups on server names */ - static bool avoid_dns = true; - static bool use_gssproxy = false; --int thread_started = false; --pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER; --pthread_cond_t pcond = PTHREAD_COND_INITIALIZER; -+pthread_mutex_t clp_lock = PTHREAD_MUTEX_INITIALIZER; -+static bool signal_received = false; -+static struct event_base *evbase = NULL; - - TAILQ_HEAD(topdir_list_head, topdir) topdir_list; - -@@ -359,20 +359,28 @@ out: - free(port); - } - -+/* Actually frees clp and fields that might be used from other -+ * threads if was last reference. -+ */ - static void --gssd_destroy_client(struct clnt_info *clp) -+gssd_free_client(struct clnt_info *clp) - { -- if (clp->krb5_fd >= 0) { -+ int refcnt; -+ -+ pthread_mutex_lock(&clp_lock); -+ refcnt = --clp->refcount; -+ pthread_mutex_unlock(&clp_lock); -+ if (refcnt > 0) -+ return; -+ -+ printerr(3, "freeing client %s\n", clp->relpath); -+ -+ if (clp->krb5_fd >= 0) - close(clp->krb5_fd); -- event_del(&clp->krb5_ev); -- } - -- if (clp->gssd_fd >= 0) { -+ if (clp->gssd_fd >= 0) - close(clp->gssd_fd); -- event_del(&clp->gssd_ev); -- } - -- inotify_rm_watch(inotify_fd, clp->wd); - free(clp->relpath); - free(clp->servicename); - free(clp->servername); -@@ -380,6 +388,30 @@ gssd_destroy_client(struct clnt_info *clp) - free(clp); - } - -+/* Called when removing from clnt_list to tear down event handling. -+ * Will then free clp if was last reference. -+ */ -+static void -+gssd_destroy_client(struct clnt_info *clp) -+{ -+ printerr(3, "destroying client %s\n", clp->relpath); -+ -+ if (clp->krb5_ev) { -+ event_del(clp->krb5_ev); -+ event_free(clp->krb5_ev); -+ clp->krb5_ev = NULL; -+ } -+ -+ if (clp->gssd_ev) { -+ event_del(clp->gssd_ev); -+ event_free(clp->gssd_ev); -+ clp->gssd_ev = NULL; -+ } -+ -+ inotify_rm_watch(inotify_fd, clp->wd); -+ gssd_free_client(clp); -+} -+ - static void gssd_scan(void); - - static int -@@ -416,11 +448,21 @@ static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp) - info = malloc(sizeof(struct clnt_upcall_info)); - if (info == NULL) - return NULL; -+ -+ pthread_mutex_lock(&clp_lock); -+ clp->refcount++; -+ pthread_mutex_unlock(&clp_lock); - info->clp = clp; - - return info; - } - -+void free_upcall_info(struct clnt_upcall_info *info) -+{ -+ gssd_free_client(info->clp); -+ free(info); -+} -+ - /* For each upcall read the upcall info into the buffer, then create a - * thread in a detached state so that resources are released back into - * the system without the need for a join. -@@ -438,13 +480,13 @@ gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) - info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf)); - if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') { - printerr(0, "WARNING: %s: failed reading request\n", __func__); -- free(info); -+ free_upcall_info(info); - return; - } - info->lbuf[info->lbuflen-1] = 0; - - if (start_upcall_thread(handle_gssd_upcall, info)) -- free(info); -+ free_upcall_info(info); - } - - static void -@@ -461,12 +503,12 @@ gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) - sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) { - printerr(0, "WARNING: %s: failed reading uid from krb5 " - "upcall pipe: %s\n", __func__, strerror(errno)); -- free(info); -+ free_upcall_info(info); - return; - } - - if (start_upcall_thread(handle_krb5_upcall, info)) -- free(info); -+ free_upcall_info(info); - } - - static struct clnt_info * -@@ -478,6 +520,8 @@ gssd_get_clnt(struct topdir *tdi, const char *name) - if (!strcmp(clp->name, name)) - return clp; - -+ printerr(3, "creating client %s/%s\n", tdi->name, name); -+ - clp = calloc(1, sizeof(struct clnt_info)); - if (!clp) { - printerr(0, "ERROR: can't malloc clnt_info: %s\n", -@@ -501,6 +545,7 @@ gssd_get_clnt(struct topdir *tdi, const char *name) - clp->name = clp->relpath + strlen(tdi->name) + 1; - clp->krb5_fd = -1; - clp->gssd_fd = -1; -+ clp->refcount = 1; - - TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list); - return clp; -@@ -515,11 +560,8 @@ static int - gssd_scan_clnt(struct clnt_info *clp) - { - int clntfd; -- bool gssd_was_closed; -- bool krb5_was_closed; - -- gssd_was_closed = clp->gssd_fd < 0 ? true : false; -- krb5_was_closed = clp->krb5_fd < 0 ? true : false; -+ printerr(3, "scanning client %s\n", clp->relpath); - - clntfd = openat(pipefs_fd, clp->relpath, O_RDONLY); - if (clntfd < 0) { -@@ -535,16 +577,30 @@ gssd_scan_clnt(struct clnt_info *clp) - if (clp->gssd_fd == -1 && clp->krb5_fd == -1) - clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK); - -- if (gssd_was_closed && clp->gssd_fd >= 0) { -- event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST, -- gssd_clnt_gssd_cb, clp); -- event_add(&clp->gssd_ev, NULL); -+ if (!clp->gssd_ev && clp->gssd_fd >= 0) { -+ clp->gssd_ev = event_new(evbase, clp->gssd_fd, EV_READ | EV_PERSIST, -+ gssd_clnt_gssd_cb, clp); -+ if (!clp->gssd_ev) { -+ printerr(0, "ERROR: %s: can't create gssd event for %s: %s\n", -+ __FUNCTION__, clp->relpath, strerror(errno)); -+ close(clp->gssd_fd); -+ clp->gssd_fd = -1; -+ } else { -+ event_add(clp->gssd_ev, NULL); -+ } - } - -- if (krb5_was_closed && clp->krb5_fd >= 0) { -- event_set(&clp->krb5_ev, clp->krb5_fd, EV_READ | EV_PERSIST, -- gssd_clnt_krb5_cb, clp); -- event_add(&clp->krb5_ev, NULL); -+ if (!clp->krb5_ev && clp->krb5_fd >= 0) { -+ clp->krb5_ev = event_new(evbase, clp->krb5_fd, EV_READ | EV_PERSIST, -+ gssd_clnt_krb5_cb, clp); -+ if (!clp->krb5_ev) { -+ printerr(0, "ERROR: %s: can't create krb5 event for %s: %s\n", -+ __FUNCTION__, clp->relpath, strerror(errno)); -+ close(clp->krb5_fd); -+ clp->krb5_fd = -1; -+ } else { -+ event_add(clp->krb5_ev, NULL); -+ } - } - - if (clp->krb5_fd == -1 && clp->gssd_fd == -1) -@@ -651,7 +707,7 @@ gssd_scan_topdir(const char *name) - if (clp->scanned) - continue; - -- printerr(3, "destroying client %s\n", clp->relpath); -+ printerr(3, "orphaned client %s\n", clp->relpath); - saveprev = clp->list.tqe_prev; - TAILQ_REMOVE(&tdi->clnt_list, clp, list); - gssd_destroy_client(clp); -@@ -748,12 +804,16 @@ gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotif - } else if (ev->mask & IN_DELETE) { - if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) { - close(clp->gssd_fd); -- event_del(&clp->gssd_ev); -+ event_del(clp->gssd_ev); -+ event_free(clp->gssd_ev); -+ clp->gssd_ev = NULL; - clp->gssd_fd = -1; - - } else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) { - close(clp->krb5_fd); -- event_del(&clp->krb5_ev); -+ event_del(clp->krb5_ev); -+ event_free(clp->krb5_ev); -+ clp->krb5_ev = NULL; - clp->krb5_fd = -1; - } - -@@ -826,10 +886,15 @@ found: - static void - sig_die(int signal) - { -- if (root_uses_machine_creds) -- gssd_destroy_krb5_machine_creds(); -+ if (signal_received) { -+ gssd_destroy_krb5_principals(root_uses_machine_creds); -+ printerr(1, "forced exiting on signal %d\n", signal); -+ exit(0); -+ } -+ -+ signal_received = true; - printerr(1, "exiting on signal %d\n", signal); -- exit(0); -+ event_base_loopexit(evbase, NULL); - } - - static void -@@ -886,9 +951,10 @@ main(int argc, char *argv[]) - int rpc_verbosity = 0; - int opt; - int i; -+ int rc; - extern char *optarg; - char *progname; -- struct event sighup_ev; -+ struct event *sighup_ev; - - read_gss_conf(); - -@@ -1027,7 +1093,11 @@ main(int argc, char *argv[]) - if (gssd_check_mechs() != 0) - errx(1, "Problem with gssapi library"); - -- event_init(); -+ evbase = event_base_new(); -+ if (!evbase) { -+ printerr(0, "ERROR: failed to create event base: %s\n", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } - - pipefs_dir = opendir(pipefs_path); - if (!pipefs_dir) { -@@ -1049,18 +1119,51 @@ main(int argc, char *argv[]) - - signal(SIGINT, sig_die); - signal(SIGTERM, sig_die); -- signal_set(&sighup_ev, SIGHUP, gssd_scan_cb, NULL); -- signal_add(&sighup_ev, NULL); -- event_set(&inotify_ev, inotify_fd, EV_READ | EV_PERSIST, gssd_inotify_cb, NULL); -- event_add(&inotify_ev, NULL); -+ sighup_ev = evsignal_new(evbase, SIGHUP, gssd_scan_cb, NULL); -+ if (!sighup_ev) { -+ printerr(0, "ERROR: failed to create SIGHUP event: %s\n", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+ evsignal_add(sighup_ev, NULL); -+ inotify_ev = event_new(evbase, inotify_fd, EV_READ | EV_PERSIST, -+ gssd_inotify_cb, NULL); -+ if (!inotify_ev) { -+ printerr(0, "ERROR: failed to create inotify event: %s\n", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+ event_add(inotify_ev, NULL); - - TAILQ_INIT(&topdir_list); - gssd_scan(); - daemon_ready(); - -- event_dispatch(); -+ rc = event_base_dispatch(evbase); - -- printerr(0, "ERROR: event_dispatch() returned!\n"); -- return EXIT_FAILURE; --} -+ printerr(0, "event_dispatch() returned %i!\n", rc); -+ -+ gssd_destroy_krb5_principals(root_uses_machine_creds); -+ -+ while (!TAILQ_EMPTY(&topdir_list)) { -+ struct topdir *tdi = TAILQ_FIRST(&topdir_list); -+ TAILQ_REMOVE(&topdir_list, tdi, list); -+ while (!TAILQ_EMPTY(&tdi->clnt_list)) { -+ struct clnt_info *clp = TAILQ_FIRST(&tdi->clnt_list); -+ TAILQ_REMOVE(&tdi->clnt_list, clp, list); -+ gssd_destroy_client(clp); -+ } -+ free(tdi); -+ } -+ -+ event_free(inotify_ev); -+ event_free(sighup_ev); -+ event_base_free(evbase); - -+ close(inotify_fd); -+ close(pipefs_fd); -+ closedir(pipefs_dir); -+ -+ free(preferred_realm); -+ free(ccachesearch); -+ -+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index f4f5975..1e8c58d 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -62,13 +62,10 @@ extern int root_uses_machine_creds; - extern unsigned int context_timeout; - extern unsigned int rpc_timeout; - extern char *preferred_realm; --extern pthread_mutex_t ple_lock; --extern pthread_cond_t pcond; --extern pthread_mutex_t pmutex; --extern int thread_started; - - struct clnt_info { - TAILQ_ENTRY(clnt_info) list; -+ int refcount; - int wd; - bool scanned; - char *name; -@@ -79,9 +76,9 @@ struct clnt_info { - int vers; - char *protocol; - int krb5_fd; -- struct event krb5_ev; -+ struct event *krb5_ev; - int gssd_fd; -- struct event gssd_ev; -+ struct event *gssd_ev; - struct sockaddr_storage addr; - }; - -@@ -94,6 +91,7 @@ struct clnt_upcall_info { - - void handle_krb5_upcall(struct clnt_upcall_info *clp); - void handle_gssd_upcall(struct clnt_upcall_info *clp); -+void free_upcall_info(struct clnt_upcall_info *info); - - - #endif /* _RPC_GSSD_H_ */ -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 8fe6605..e830f49 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -149,9 +149,10 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - char *buf = NULL, *p = NULL, *end = NULL; - unsigned int timeout = context_timeout; - unsigned int buf_size = 0; -+ pthread_t tid = pthread_self(); - -- printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", -- lifetime_rec, acceptor->length, acceptor->value); -+ printerr(2, "do_downcall(0x%x): lifetime_rec=%u acceptor=%.*s\n", -+ tid, lifetime_rec, acceptor->length, acceptor->value); - buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + - sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + - sizeof(context_token->length) + context_token->length + -@@ -177,7 +178,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - return; - out_err: - free(buf); -- printerr(1, "Failed to write downcall!\n"); -+ printerr(1, "do_downcall(0x%x): Failed to write downcall!\n", tid); - return; - } - -@@ -231,7 +232,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen, - switch (sa->sa_family) { - case AF_INET: - if (s4->sin_port != 0) { -- printerr(2, "DEBUG: port already set to %d\n", -+ printerr(4, "DEBUG: port already set to %d\n", - ntohs(s4->sin_port)); - return 1; - } -@@ -239,7 +240,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen, - #ifdef IPV6_SUPPORTED - case AF_INET6: - if (s6->sin6_port != 0) { -- printerr(2, "DEBUG: port already set to %d\n", -+ printerr(4, "DEBUG: port already set to %d\n", - ntohs(s6->sin6_port)); - return 1; - } -@@ -548,7 +549,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, - uid, tgtname); - - do { -- gssd_refresh_krb5_machine_credential(clp->servername, NULL, -+ gssd_refresh_krb5_machine_credential(clp->servername, - service, srchost); - /* - * Get a list of credential cache names and try each -@@ -730,7 +731,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info) - printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); - - process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL); -- free(info); -+ free_upcall_info(info); - } - - void -@@ -747,8 +748,10 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - char *enctypes = NULL; - char *upcall_str; - char *pbuf = info->lbuf; -+ pthread_t tid = pthread_self(); - -- printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); -+ printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid, -+ info->lbuf, clp->relpath); - - upcall_str = strdup(info->lbuf); - if (upcall_str == NULL) { -@@ -830,6 +833,6 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - out: - free(upcall_str); - out_nomem: -- free(info); -+ free_upcall_info(info); - return; - } -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 8c73748..9bd74b0 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -130,9 +130,28 @@ - #include "gss_util.h" - #include "krb5_util.h" - -+/* -+ * List of principals from our keytab that we -+ * will try to use to obtain credentials -+ * (known as a principal list entry (ple)) -+ */ -+struct gssd_k5_kt_princ { -+ struct gssd_k5_kt_princ *next; -+ // Only protect against deletion, not modification -+ int refcount; -+ // Only set during creation in new_ple() -+ krb5_principal princ; -+ char *realm; -+ // Modified during usage by gssd_get_single_krb5_cred() -+ char *ccname; -+ krb5_timestamp endtime; -+}; -+ -+ - /* Global list of principals/cache file names for machine credentials */ --struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; --pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER; -+static struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; -+/* This mutex protects list modification & ple->ccname */ -+static pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER; - - #ifdef HAVE_SET_ALLOWABLE_ENCTYPES - int limit_to_legacy_enctypes = 0; -@@ -146,10 +165,22 @@ static int select_krb5_ccache(const struct dirent *d); - static int gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, - const char **cctype, struct dirent **d); - static int gssd_get_single_krb5_cred(krb5_context context, -- krb5_keytab kt, struct gssd_k5_kt_princ *ple, int nocache); -+ krb5_keytab kt, struct gssd_k5_kt_princ *ple); - static int query_krb5_ccache(const char* cred_cache, char **ret_princname, - char **ret_realm); - -+static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple) -+{ -+ if (--ple->refcount) -+ return; -+ -+ printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n", ple->ccname, ple->realm); -+ krb5_free_principal(context, ple->princ); -+ free(ple->ccname); -+ free(ple->realm); -+ free(ple); -+} -+ - /* - * Called from the scandir function to weed out potential krb5 - * credentials cache files -@@ -192,7 +223,8 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, - int found = 0; - struct dirent *best_match_dir = NULL; - struct stat best_match_stat, tmp_stat; -- char buf[PATH_MAX+4+2+256]; -+ /* dirname + cctype + d_name + NULL */ -+ char buf[PATH_MAX+5+256+1]; - char *princname = NULL; - char *realm = NULL; - int score, best_match_score = 0, err = -EACCES; -@@ -349,8 +381,7 @@ gssd_check_if_cc_exists(struct gssd_k5_kt_princ *ple) - static int - gssd_get_single_krb5_cred(krb5_context context, - krb5_keytab kt, -- struct gssd_k5_kt_princ *ple, -- int nocache) -+ struct gssd_k5_kt_princ *ple) - { - #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS - krb5_get_init_creds_opt *init_opts = NULL; -@@ -367,22 +398,26 @@ gssd_get_single_krb5_cred(krb5_context context, - char *cache_type; - char *pname = NULL; - char *k5err = NULL; -+ int nocache = 0; - - memset(&my_creds, 0, sizeof(my_creds)); - -- if (!nocache && !use_memcache) -+ if (!use_memcache) - nocache = gssd_check_if_cc_exists(ple); - /* - * Workaround for clock skew among NFS server, NFS client and KDC - * 300 because clock skew must be within 300sec for kerberos - */ - now += 300; -+ pthread_mutex_lock(&ple_lock); - if (ple->ccname && ple->endtime > now && !nocache) { - printerr(3, "INFO: Credentials in CC '%s' are good until %d\n", - ple->ccname, ple->endtime); - code = 0; -+ pthread_mutex_unlock(&ple_lock); - goto out; - } -+ pthread_mutex_unlock(&ple_lock); - - if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { - printerr(0, "ERROR: Unable to get keytab name in " -@@ -435,6 +470,7 @@ gssd_get_single_krb5_cred(krb5_context context, - * Initialize cache file which we're going to be using - */ - -+ pthread_mutex_lock(&ple_lock); - if (use_memcache) - cache_type = "MEMORY"; - else -@@ -444,15 +480,18 @@ gssd_get_single_krb5_cred(krb5_context context, - ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, - GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); - ple->endtime = my_creds.times.endtime; -- if (ple->ccname != NULL) -+ if (ple->ccname == NULL || strcmp(ple->ccname, cc_name) != 0) { - free(ple->ccname); -- ple->ccname = strdup(cc_name); -- if (ple->ccname == NULL) { -- printerr(0, "ERROR: no storage to duplicate credentials " -- "cache name '%s'\n", cc_name); -- code = ENOMEM; -- goto out; -+ ple->ccname = strdup(cc_name); -+ if (ple->ccname == NULL) { -+ printerr(0, "ERROR: no storage to duplicate credentials " -+ "cache name '%s'\n", cc_name); -+ code = ENOMEM; -+ pthread_mutex_unlock(&ple_lock); -+ goto out; -+ } - } -+ pthread_mutex_unlock(&ple_lock); - if ((code = krb5_cc_resolve(context, cc_name, &ccache))) { - k5err = gssd_k5_err_msg(context, code); - printerr(0, "ERROR: %s while opening credential cache '%s'\n", -@@ -484,12 +523,13 @@ gssd_get_single_krb5_cred(krb5_context context, - if (ccache) - krb5_cc_close(context, ccache); - krb5_free_cred_contents(context, &my_creds); -- krb5_free_string(context, k5err); -+ free(k5err); - return (code); - } - - /* - * Given a principal, find a matching ple structure -+ * Called with mutex held - */ - static struct gssd_k5_kt_princ * - find_ple_by_princ(krb5_context context, krb5_principal princ) -@@ -506,6 +546,7 @@ find_ple_by_princ(krb5_context context, krb5_principal princ) - - /* - * Create, initialize, and add a new ple structure to the global list -+ * Called with mutex held - */ - static struct gssd_k5_kt_princ * - new_ple(krb5_context context, krb5_principal princ) -@@ -557,6 +598,7 @@ new_ple(krb5_context context, krb5_principal princ) - p->next = ple; - } - -+ ple->refcount = 1; - return ple; - outerr: - if (ple) { -@@ -575,13 +617,14 @@ get_ple_by_princ(krb5_context context, krb5_principal princ) - { - struct gssd_k5_kt_princ *ple; - -- /* Need to serialize list if we ever become multi-threaded! */ -- - pthread_mutex_lock(&ple_lock); - ple = find_ple_by_princ(context, princ); - if (ple == NULL) { - ple = new_ple(context, princ); - } -+ if (ple != NULL) { -+ ple->refcount++; -+ } - pthread_mutex_unlock(&ple_lock); - - return ple; -@@ -715,6 +758,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - goto out; - } - -+ printerr(4, "Scanning keytab for %s/*@%s\n", service, realm); - while ((code = krb5_kt_next_entry(context, kt, kte, &cursor)) == 0) { - if ((code = krb5_unparse_name(context, kte->principal, - &pname))) { -@@ -723,7 +767,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - "we failed to unparse principal name: %s\n", - k5err); - k5_free_kt_entry(context, kte); -- krb5_free_string(context, k5err); -+ free(k5err); - k5err = NULL; - continue; - } -@@ -746,6 +790,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - retval = ENOMEM; - k5_free_kt_entry(context, kte); - } else { -+ release_ple(context, ple); -+ ple = NULL; - retval = 0; - *found = 1; - } -@@ -770,7 +816,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - if (retval < 0) - retval = 0; - out: -- krb5_free_string(context, k5err); -+ free(k5err); - return retval; - } - -@@ -811,41 +857,42 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, - /* Get full local hostname */ - if (srchost) { - strcpy(myhostname, srchost); -- } else if (gethostname(myhostname, sizeof(myhostname)) == -1) { -- retval = errno; -- k5err = gssd_k5_err_msg(context, retval); -- printerr(1, "%s while getting local hostname\n", k5err); -- goto out; -+ strcpy(myhostad, myhostname); -+ } else { -+ /* Borrow myhostad for gethostname(), we need it later anyways */ -+ if (gethostname(myhostad, sizeof(myhostad)-1) == -1) { -+ retval = errno; -+ k5err = gssd_k5_err_msg(context, retval); -+ printerr(1, "%s while getting local hostname\n", k5err); -+ goto out; -+ } -+ retval = get_full_hostname(myhostad, myhostname, sizeof(myhostname)); -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - } - - /* Compute the active directory machine name HOST$ */ -- krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", -+ krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", - notsetstr, &adhostoverride); -- if (strcmp(adhostoverride, notsetstr) != 0) { -- printerr (1, -- "AD host string overridden with \"%s\" from appdefaults\n", -- adhostoverride); -- /* No overflow: Windows cannot handle strings longer than 19 chars */ -- strcpy(myhostad, adhostoverride); -+ if (adhostoverride && strcmp(adhostoverride, notsetstr) != 0) { -+ printerr(1, -+ "AD host string overridden with \"%s\" from appdefaults\n", -+ adhostoverride); -+ /* No overflow: Windows cannot handle strings longer than 19 chars */ -+ strcpy(myhostad, adhostoverride); - } else { -- strcpy(myhostad, myhostname); -- for (i = 0; myhostad[i] != 0; ++i) { -- if (myhostad[i] == '.') break; -- } -- myhostad[i] = '$'; -- myhostad[i+1] = 0; -+ /* In this case, it's been pre-filled above */ -+ for (i = 0; myhostad[i] != 0; ++i) { -+ if (myhostad[i] == '.') break; -+ } -+ myhostad[i] = '$'; -+ myhostad[i+1] = 0; - } - if (adhostoverride) - krb5_free_string(context, adhostoverride); - -- if (!srchost) { -- retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) { -- /* Don't use myhostname */ -- myhostname[0] = 0; -- } -- } -- - code = krb5_get_default_realm(context, &default_realm); - if (code) { - retval = code; -@@ -927,7 +974,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, - k5err = gssd_k5_err_msg(context, code); - printerr(1, "%s while building principal for '%s'\n", - k5err, spn); -- krb5_free_string(context, k5err); -+ free(k5err); - k5err = NULL; - continue; - } -@@ -937,7 +984,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, - k5err = gssd_k5_err_msg(context, code); - printerr(3, "%s while getting keytab entry for '%s'\n", - k5err, spn); -- krb5_free_string(context, k5err); -+ free(k5err); - k5err = NULL; - /* - * We tried the active directory machine account -@@ -986,7 +1033,7 @@ out: - k5_free_default_realm(context, default_realm); - if (realmnames) - krb5_free_host_realm(context, realmnames); -- krb5_free_string(context, k5err); -+ free(k5err); - return retval; - } - -@@ -1078,6 +1125,93 @@ err_cache: - return (*ret_princname && *ret_realm); - } - -+/* -+ * Obtain (or refresh if necessary) Kerberos machine credentials -+ * If a ple is passed in, it's reference will be released -+ */ -+static int -+gssd_refresh_krb5_machine_credential_internal(char *hostname, -+ struct gssd_k5_kt_princ *ple, -+ char *service, char *srchost) -+{ -+ krb5_error_code code = 0; -+ krb5_context context; -+ krb5_keytab kt = NULL;; -+ int retval = 0; -+ char *k5err = NULL; -+ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; -+ -+ printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n", -+ __func__, hostname, ple, service, srchost); -+ -+ /* -+ * If a specific service name was specified, use it. -+ * Otherwise, use the default list. -+ */ -+ if (service != NULL && strcmp(service, "*") != 0) { -+ svcnames[0] = service; -+ svcnames[1] = NULL; -+ } -+ if (hostname == NULL && ple == NULL) -+ return EINVAL; -+ -+ code = krb5_init_context(&context); -+ if (code) { -+ k5err = gssd_k5_err_msg(NULL, code); -+ printerr(0, "ERROR: %s: %s while initializing krb5 context\n", -+ __func__, k5err); -+ retval = code; -+ goto out; -+ } -+ -+ if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { -+ k5err = gssd_k5_err_msg(context, code); -+ printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", -+ __func__, k5err, keytabfile); -+ goto out_free_context; -+ } -+ -+ if (ple == NULL) { -+ krb5_keytab_entry kte; -+ -+ code = find_keytab_entry(context, kt, srchost, hostname, -+ &kte, svcnames); -+ if (code) { -+ printerr(0, "ERROR: %s: no usable keytab entry found " -+ "in keytab %s for connection with host %s\n", -+ __FUNCTION__, keytabfile, hostname); -+ retval = code; -+ goto out_free_kt; -+ } -+ -+ ple = get_ple_by_princ(context, kte.principal); -+ k5_free_kt_entry(context, &kte); -+ if (ple == NULL) { -+ char *pname; -+ if ((krb5_unparse_name(context, kte.principal, &pname))) { -+ pname = NULL; -+ } -+ printerr(0, "ERROR: %s: Could not locate or create " -+ "ple struct for principal %s for connection " -+ "with host %s\n", -+ __FUNCTION__, pname ? pname : "", -+ hostname); -+ if (pname) k5_free_unparsed_name(context, pname); -+ goto out_free_kt; -+ } -+ } -+ retval = gssd_get_single_krb5_cred(context, kt, ple); -+out_free_kt: -+ krb5_kt_close(context, kt); -+out_free_context: -+ if (ple) -+ release_ple(context, ple); -+ krb5_free_context(context); -+out: -+ free(k5err); -+ return retval; -+} -+ - /*==========================*/ - /*=== External routines ===*/ - /*==========================*/ -@@ -1092,7 +1226,8 @@ err_cache: - int - gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) - { -- char buf[PATH_MAX+2+256], dirname[PATH_MAX]; -+ /* dirname + cctype + d_name + NULL */ -+ char buf[PATH_MAX+5+256+1], dirname[PATH_MAX]; - const char *cctype; - struct dirent *d; - int err, i, j; -@@ -1171,37 +1306,56 @@ gssd_get_krb5_machine_cred_list(char ***list) - goto out; - } - -- /* Need to serialize list if we ever become multi-threaded! */ -- -+ pthread_mutex_lock(&ple_lock); - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { -- if (ple->ccname) { -- /* Make sure cred is up-to-date before returning it */ -- retval = gssd_refresh_krb5_machine_credential(NULL, ple, -- NULL, NULL); -- if (retval) -- continue; -- if (i + 1 > listsize) { -- listsize += listinc; -- l = (char **) -- realloc(l, listsize * sizeof(char *)); -- if (l == NULL) { -- retval = ENOMEM; -- goto out; -- } -- } -- if ((l[i++] = strdup(ple->ccname)) == NULL) { -+ if (!ple->ccname) -+ continue; -+ -+ /* Take advantage of the fact we only remove the ple -+ * from the list during shutdown. If it's modified -+ * concurrently at worst we'll just miss a new entry -+ * before the current ple -+ * -+ * gssd_refresh_krb5_machine_credential_internal() will -+ * release the ple refcount -+ */ -+ ple->refcount++; -+ pthread_mutex_unlock(&ple_lock); -+ /* Make sure cred is up-to-date before returning it */ -+ retval = gssd_refresh_krb5_machine_credential_internal(NULL, ple, -+ NULL, NULL); -+ pthread_mutex_lock(&ple_lock); -+ if (gssd_k5_kt_princ_list == NULL) { -+ /* Looks like we did shutdown... abort */ -+ l[i] = NULL; -+ gssd_free_krb5_machine_cred_list(l); -+ retval = ENOMEM; -+ goto out_lock; -+ } -+ if (retval) -+ continue; -+ if (i + 1 > listsize) { -+ listsize += listinc; -+ l = (char **) -+ realloc(l, listsize * sizeof(char *)); -+ if (l == NULL) { - retval = ENOMEM; -- goto out; -+ goto out_lock; - } - } -+ if ((l[i++] = strdup(ple->ccname)) == NULL) { -+ retval = ENOMEM; -+ goto out_lock; -+ } - } - if (i > 0) { - l[i] = NULL; - *list = l; - retval = 0; -- goto out; - } else - free((void *)l); -+out_lock: -+ pthread_mutex_unlock(&ple_lock); - out: - return retval; - } -@@ -1226,7 +1380,7 @@ gssd_free_krb5_machine_cred_list(char **list) - * Called upon exit. Destroys machine credentials. - */ - void --gssd_destroy_krb5_machine_creds(void) -+gssd_destroy_krb5_principals(int destroy_machine_creds) - { - krb5_context context; - krb5_error_code code = 0; -@@ -1238,33 +1392,38 @@ gssd_destroy_krb5_machine_creds(void) - if (code) { - k5err = gssd_k5_err_msg(NULL, code); - printerr(0, "ERROR: %s while initializing krb5\n", k5err); -- goto out; -+ free(k5err); -+ return; - } - -- for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { -- if (!ple->ccname) -- continue; -- if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { -- k5err = gssd_k5_err_msg(context, code); -- printerr(0, "WARNING: %s while resolving credential " -- "cache '%s' for destruction\n", k5err, -- ple->ccname); -- krb5_free_string(context, k5err); -- k5err = NULL; -- continue; -- } -+ pthread_mutex_lock(&ple_lock); -+ while (gssd_k5_kt_princ_list) { -+ ple = gssd_k5_kt_princ_list; -+ gssd_k5_kt_princ_list = ple->next; - -- if ((code = krb5_cc_destroy(context, ccache))) { -- k5err = gssd_k5_err_msg(context, code); -- printerr(0, "WARNING: %s while destroying credential " -- "cache '%s'\n", k5err, ple->ccname); -- krb5_free_string(context, k5err); -- k5err = NULL; -+ if (destroy_machine_creds && ple->ccname) { -+ if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { -+ k5err = gssd_k5_err_msg(context, code); -+ printerr(0, "WARNING: %s while resolving credential " -+ "cache '%s' for destruction\n", k5err, -+ ple->ccname); -+ free(k5err); -+ k5err = NULL; -+ } -+ -+ if (!code && (code = krb5_cc_destroy(context, ccache))) { -+ k5err = gssd_k5_err_msg(context, code); -+ printerr(0, "WARNING: %s while destroying credential " -+ "cache '%s'\n", k5err, ple->ccname); -+ free(k5err); -+ k5err = NULL; -+ } - } -+ -+ release_ple(context, ple); - } -+ pthread_mutex_unlock(&ple_lock); - krb5_free_context(context); -- out: -- krb5_free_string(context, k5err); - } - - /* -@@ -1272,83 +1431,10 @@ gssd_destroy_krb5_machine_creds(void) - */ - int - gssd_refresh_krb5_machine_credential(char *hostname, -- struct gssd_k5_kt_princ *ple, - char *service, char *srchost) - { -- krb5_error_code code = 0; -- krb5_context context; -- krb5_keytab kt = NULL;; -- int retval = 0; -- char *k5err = NULL; -- const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; -- -- printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n", -- __func__, hostname, ple, service, srchost); -- -- /* -- * If a specific service name was specified, use it. -- * Otherwise, use the default list. -- */ -- if (service != NULL && strcmp(service, "*") != 0) { -- svcnames[0] = service; -- svcnames[1] = NULL; -- } -- if (hostname == NULL && ple == NULL) -- return EINVAL; -- -- code = krb5_init_context(&context); -- if (code) { -- k5err = gssd_k5_err_msg(NULL, code); -- printerr(0, "ERROR: %s: %s while initializing krb5 context\n", -- __func__, k5err); -- retval = code; -- goto out; -- } -- -- if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { -- k5err = gssd_k5_err_msg(context, code); -- printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", -- __func__, k5err, keytabfile); -- goto out_free_context; -- } -- -- if (ple == NULL) { -- krb5_keytab_entry kte; -- -- code = find_keytab_entry(context, kt, srchost, hostname, -- &kte, svcnames); -- if (code) { -- printerr(0, "ERROR: %s: no usable keytab entry found " -- "in keytab %s for connection with host %s\n", -- __FUNCTION__, keytabfile, hostname); -- retval = code; -- goto out_free_kt; -- } -- -- ple = get_ple_by_princ(context, kte.principal); -- k5_free_kt_entry(context, &kte); -- if (ple == NULL) { -- char *pname; -- if ((krb5_unparse_name(context, kte.principal, &pname))) { -- pname = NULL; -- } -- printerr(0, "ERROR: %s: Could not locate or create " -- "ple struct for principal %s for connection " -- "with host %s\n", -- __FUNCTION__, pname ? pname : "", -- hostname); -- if (pname) k5_free_unparsed_name(context, pname); -- goto out_free_kt; -- } -- } -- retval = gssd_get_single_krb5_cred(context, kt, ple, 0); --out_free_kt: -- krb5_kt_close(context, kt); --out_free_context: -- krb5_free_context(context); --out: -- krb5_free_string(context, k5err); -- return retval; -+ return gssd_refresh_krb5_machine_credential_internal(hostname, NULL, -+ service, srchost); - } - - /* -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index b000b44..2415205 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -9,27 +9,13 @@ - #include "gss_oids.h" - #endif - --/* -- * List of principals from our keytab that we -- * will try to use to obtain credentials -- * (known as a principal list entry (ple)) -- */ --struct gssd_k5_kt_princ { -- struct gssd_k5_kt_princ *next; -- krb5_principal princ; -- char *ccname; -- char *realm; -- krb5_timestamp endtime; --}; -- - - int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, - char *dirname); - int gssd_get_krb5_machine_cred_list(char ***list); - void gssd_free_krb5_machine_cred_list(char **list); --void gssd_destroy_krb5_machine_creds(void); -+void gssd_destroy_krb5_principals(int destroy_machine_creds); - int gssd_refresh_krb5_machine_credential(char *hostname, -- struct gssd_k5_kt_princ *ple, - char *service, char *srchost); - char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); - void gssd_k5_get_default_realm(char **def_realm); -diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c -index ec49b61..3ab2100 100644 ---- a/utils/gssd/svcgssd.c -+++ b/utils/gssd/svcgssd.c -@@ -57,20 +57,36 @@ - #include - #include - #include -+#include -+ - #include "nfslib.h" - #include "svcgssd.h" - #include "gss_util.h" - #include "err_util.h" - #include "conffile.h" -+#include "misc.h" -+#include "svcgssd_krb5.h" -+ -+struct state_paths etab; /* from cacheio.c */ -+static bool signal_received = false; -+static struct event_base *evbase = NULL; -+static int nullrpc_fd = -1; -+static struct event *nullrpc_event = NULL; -+static struct event *wait_event = NULL; - --struct state_paths etab; -+#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" - - static void - sig_die(int signal) - { -- /* destroy krb5 machine creds */ -+ if (signal_received) { -+ /* destroy krb5 machine creds */ -+ printerr(1, "forced exiting on signal %d\n", signal); -+ exit(0); -+ } -+ signal_received = true; - printerr(1, "exiting on signal %d\n", signal); -- exit(0); -+ event_base_loopexit(evbase, NULL); - } - - static void -@@ -89,6 +105,84 @@ usage(char *progname) - exit(1); - } - -+static void -+svcgssd_nullrpc_cb(int fd, short UNUSED(which), void *UNUSED(data)) -+{ -+ char lbuf[RPC_CHAN_BUF_SIZE]; -+ int lbuflen = 0; -+ -+ printerr(1, "reading null request\n"); -+ -+ lbuflen = read(fd, lbuf, sizeof(lbuf)); -+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { -+ printerr(0, "WARNING: handle_nullreq: failed reading request\n"); -+ return; -+ } -+ lbuf[lbuflen-1] = 0; -+ -+ handle_nullreq(lbuf); -+} -+ -+static void -+svcgssd_nullrpc_close(void) -+{ -+ if (nullrpc_event) { -+ printerr(2, "closing nullrpc channel %s\n", NULLRPC_FILE); -+ event_free(nullrpc_event); -+ nullrpc_event = NULL; -+ } -+ if (nullrpc_fd != -1) { -+ close(nullrpc_fd); -+ nullrpc_fd = -1; -+ } -+} -+ -+static void -+svcgssd_nullrpc_open(void) -+{ -+ nullrpc_fd = open(NULLRPC_FILE, O_RDWR); -+ if (nullrpc_fd < 0) { -+ printerr(0, "failed to open %s: %s\n", -+ NULLRPC_FILE, strerror(errno)); -+ return; -+ } -+ nullrpc_event = event_new(evbase, nullrpc_fd, EV_READ | EV_PERSIST, -+ svcgssd_nullrpc_cb, NULL); -+ if (!nullrpc_event) { -+ printerr(0, "failed to create event for %s: %s\n", -+ NULLRPC_FILE, strerror(errno)); -+ close(nullrpc_fd); -+ nullrpc_fd = -1; -+ return; -+ } -+ event_add(nullrpc_event, NULL); -+ printerr(2, "opened nullrpc channel %s\n", NULLRPC_FILE); -+} -+ -+static void -+svcgssd_wait_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) -+{ -+ static int times = 0; -+ int rc; -+ -+ rc = access(NULLRPC_FILE, R_OK | W_OK); -+ if (rc != 0) { -+ struct timeval t = {times < 10 ? 1 : 10, 0}; -+ times++; -+ if (times % 30 == 0) -+ printerr(2, "still waiting for nullrpc channel: %s\n", -+ NULLRPC_FILE); -+ evtimer_add(wait_event, &t); -+ return; -+ } -+ -+ svcgssd_nullrpc_open(); -+ event_free(wait_event); -+ wait_event = NULL; -+} -+ -+ -+ - int - main(int argc, char *argv[]) - { -@@ -102,6 +196,7 @@ main(int argc, char *argv[]) - char *progname; - char *principal = NULL; - char *s; -+ int rc; - - conf_init_file(NFS_CONFFILE); - -@@ -117,6 +212,9 @@ main(int argc, char *argv[]) - rpc_verbosity = conf_get_num("svcgssd", "RPC-Verbosity", rpc_verbosity); - idmap_verbosity = conf_get_num("svcgssd", "IDMAP-Verbosity", idmap_verbosity); - -+ /* We don't need the config anymore */ -+ conf_cleanup(); -+ - while ((opt = getopt(argc, argv, "fivrnp:")) != -1) { - switch (opt) { - case 'f': -@@ -182,6 +280,12 @@ main(int argc, char *argv[]) - - daemon_init(fg); - -+ evbase = event_base_new(); -+ if (!evbase) { -+ printerr(0, "ERROR: failed to create event base: %s\n", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+ - signal(SIGINT, sig_die); - signal(SIGTERM, sig_die); - signal(SIGHUP, sig_hup); -@@ -209,10 +313,37 @@ main(int argc, char *argv[]) - } - } - -+ svcgssd_nullrpc_open(); -+ if (!nullrpc_event) { -+ struct timeval t = {1, 0}; -+ -+ printerr(2, "waiting for nullrpc channel to appear\n"); -+ wait_event = evtimer_new(evbase, svcgssd_wait_cb, NULL); -+ if (!wait_event) { -+ printerr(0, "ERROR: failed to create wait event: %s\n", -+ strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+ evtimer_add(wait_event, &t); -+ } -+ - daemon_ready(); - - nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ -- gssd_run(); -- printerr(0, "gssd_run returned!\n"); -- abort(); -+ -+ rc = event_base_dispatch(evbase); -+ if (rc < 0) -+ printerr(0, "event_base_dispatch() returned %i!\n", rc); -+ -+ svcgssd_nullrpc_close(); -+ if (wait_event) -+ event_free(wait_event); -+ -+ event_base_free(evbase); -+ -+ nfs4_term_name_mapping(); -+ svcgssd_free_enctypes(); -+ gssd_cleanup(); -+ -+ return EXIT_SUCCESS; - } -diff --git a/utils/gssd/svcgssd.h b/utils/gssd/svcgssd.h -index 02b5c7a..e229b98 100644 ---- a/utils/gssd/svcgssd.h -+++ b/utils/gssd/svcgssd.h -@@ -35,8 +35,7 @@ - #include - #include - --void handle_nullreq(int f); --void gssd_run(void); -+void handle_nullreq(char *cp); - - #define GSSD_SERVICE_NAME "nfs" - -diff --git a/utils/gssd/svcgssd_krb5.c b/utils/gssd/svcgssd_krb5.c -index 1d44d34..305d475 100644 ---- a/utils/gssd/svcgssd_krb5.c -+++ b/utils/gssd/svcgssd_krb5.c -@@ -74,13 +74,7 @@ parse_enctypes(char *enctypes) - return 0; - - /* Free any existing cached_enctypes */ -- free(cached_enctypes); -- -- if (parsed_enctypes != NULL) { -- free(parsed_enctypes); -- parsed_enctypes = NULL; -- parsed_num_enctypes = 0; -- } -+ svcgssd_free_enctypes(); - - /* count the number of commas */ - for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { -@@ -162,6 +156,19 @@ out_clean_parsed: - /*=== External routines ===*/ - /*==========================*/ - -+void -+svcgssd_free_enctypes(void) -+{ -+ free(cached_enctypes); -+ cached_enctypes = NULL; -+ -+ if (parsed_enctypes != NULL) { -+ free(parsed_enctypes); -+ parsed_enctypes = NULL; -+ parsed_num_enctypes = 0; -+ } -+} -+ - /* - * Get encryption types supported by the kernel, and then - * call gss_krb5_set_allowable_enctypes() to limit the -diff --git a/utils/gssd/svcgssd_krb5.h b/utils/gssd/svcgssd_krb5.h -index 07d5eb9..78a90e9 100644 ---- a/utils/gssd/svcgssd_krb5.h -+++ b/utils/gssd/svcgssd_krb5.h -@@ -32,5 +32,6 @@ - #define SVCGSSD_KRB5_H - - int svcgssd_limit_krb5_enctypes(void); -+void svcgssd_free_enctypes(void); - - #endif /* SVCGSSD_KRB5_H */ -diff --git a/utils/gssd/svcgssd_main_loop.c b/utils/gssd/svcgssd_main_loop.c -deleted file mode 100644 -index 920520d..0000000 ---- a/utils/gssd/svcgssd_main_loop.c -+++ /dev/null -@@ -1,94 +0,0 @@ --/* -- Copyright (c) 2004 The Regents of the University of Michigan. -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- 3. Neither the name of the University nor the names of its -- contributors may be used to endorse or promote products derived -- from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --*/ -- --#ifdef HAVE_CONFIG_H --#include --#endif /* HAVE_CONFIG_H */ -- --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include --#include --#include --#include -- --#include "svcgssd.h" --#include "err_util.h" -- --void --gssd_run() --{ -- int ret; -- int f; -- struct pollfd pollfd; -- --#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" -- -- f = open(NULLRPC_FILE, O_RDWR); -- if (f < 0) { -- printerr(0, "failed to open %s: %s\n", -- NULLRPC_FILE, strerror(errno)); -- exit(1); -- } -- pollfd.fd = f; -- pollfd.events = POLLIN; -- while (1) { -- int save_err; -- -- pollfd.revents = 0; -- printerr(1, "entering poll\n"); -- ret = poll(&pollfd, 1, -1); -- save_err = errno; -- printerr(1, "leaving poll\n"); -- if (ret < 0) { -- if (save_err != EINTR) -- printerr(0, "error return from poll: %s\n", -- strerror(save_err)); -- } else if (ret == 0) { -- /* timeout; shouldn't happen. */ -- } else { -- if (ret != 1) { -- printerr(0, "bug: unexpected poll return %d\n", -- ret); -- exit(1); -- } -- if (pollfd.revents & POLLIN) -- handle_nullreq(f); -- } -- } --} -diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c -index 72ec254..b403143 100644 ---- a/utils/gssd/svcgssd_proc.c -+++ b/utils/gssd/svcgssd_proc.c -@@ -318,7 +318,7 @@ print_hexl(const char *description, unsigned char *cp, int length) - #endif - - void --handle_nullreq(int f) { -+handle_nullreq(char *cp) { - /* XXX initialize to a random integer to reduce chances of unnecessary - * invalidation of existing ctx's on restarting svcgssd. */ - static u_int32_t handle_seq = 0; -@@ -340,24 +340,11 @@ handle_nullreq(int f) { - u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; - u_int32_t ignore_min_stat; - struct svc_cred cred; -- char lbuf[RPC_CHAN_BUF_SIZE]; -- int lbuflen = 0; -- char *cp; - int32_t ctx_endtime; - char *hostbased_name = NULL; - - printerr(1, "handling null request\n"); - -- lbuflen = read(f, lbuf, sizeof(lbuf)); -- if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { -- printerr(0, "WARNING: handle_nullreq: " -- "failed reading request\n"); -- return; -- } -- lbuf[lbuflen-1] = 0; -- -- cp = lbuf; -- - in_handle.length = (size_t) qword_get(&cp, in_handle.value, - sizeof(in_handle_buf)); - #ifdef DEBUG -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 893159f..f3d2314 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -49,7 +49,7 @@ - - #include - #include --#include -+#include - #include - #include - #include -@@ -115,7 +115,7 @@ struct idmap_client { - int ic_fd; - int ic_dirfd; - int ic_scanned; -- struct event ic_event; -+ struct event *ic_event; - TAILQ_ENTRY(idmap_client) ic_next; - }; - static struct idmap_client nfsd_ic[2] = { -@@ -155,6 +155,7 @@ static void idtonameres(struct idmap_msg *); - static void nametoidres(struct idmap_msg *); - - static int nfsdopen(void); -+static void nfsdclose(void); - static int nfsdopenone(struct idmap_client *); - static void nfsdreopen_one(struct idmap_client *); - static void nfsdreopen(void); -@@ -166,6 +167,22 @@ static char pipefsdir[PATH_MAX]; - static char *nobodyuser, *nobodygroup; - static uid_t nobodyuid; - static gid_t nobodygid; -+static struct event_base *evbase = NULL; -+static bool signal_received = false; -+static int inotify_fd = -1; -+ -+static void -+sig_die(int signal) -+{ -+ if (signal_received) { -+ xlog_warn("forced exiting on signal %d\n", signal); -+ exit(0); -+ } -+ -+ signal_received = true; -+ xlog_warn("exiting on signal %d\n", signal); -+ event_base_loopexit(evbase, NULL); -+} - - static int - flush_nfsd_cache(char *path, time_t now) -@@ -209,14 +226,14 @@ main(int argc, char **argv) - { - int wd = -1, opt, fg = 0, nfsdret = -1; - struct idmap_clientq icq; -- struct event rootdirev, clntdirev, svrdirev, inotifyev; -- struct event initialize; -+ struct event *rootdirev = NULL, *clntdirev = NULL, -+ *svrdirev = NULL, *inotifyev = NULL; -+ struct event *initialize = NULL; - struct passwd *pw; - struct group *gr; - struct stat sb; - char *xpipefsdir = NULL; - int serverstart = 1, clientstart = 1; -- int inotify_fd; - int ret; - char *progname; - char *conf_path = NULL; -@@ -289,6 +306,9 @@ main(int argc, char **argv) - serverstart = 0; - } - -+ /* Config memory is no longer needed */ -+ conf_cleanup(); -+ - while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) - switch (opt) { - case 'v': -@@ -341,9 +361,11 @@ main(int argc, char **argv) - if (nfs4_init_name_mapping(conf_path)) - errx(1, "Unable to create name to user id mappings."); - -- event_init(); -+ evbase = event_base_new(); -+ if (evbase == NULL) -+ errx(1, "Failed to create event base."); - -- if (verbose > 0) -+ if (verbose > 1) - xlog_warn("Expiration time is %d seconds.", - cache_entry_expiration); - if (serverstart) { -@@ -388,30 +410,44 @@ main(int argc, char **argv) - if (inotify_fd == -1) { - xlog_err("Unable to initialise inotify_init1: %s\n", strerror(errno)); - } else { -- wd = inotify_add_watch(inotify_fd, pipefsdir, IN_CREATE | IN_DELETE | IN_MODIFY); -+ wd = inotify_add_watch(inotify_fd, pipefsdir, IN_CREATE | IN_DELETE); - if (wd < 0) - xlog_err("Unable to inotify_add_watch(%s): %s\n", pipefsdir, strerror(errno)); - } - - TAILQ_INIT(&icq); - -+ signal(SIGINT, sig_die); -+ signal(SIGTERM, sig_die); -+ - /* These events are persistent */ -- signal_set(&rootdirev, SIGUSR1, dirscancb, &icq); -- signal_add(&rootdirev, NULL); -- signal_set(&clntdirev, SIGUSR2, clntscancb, &icq); -- signal_add(&clntdirev, NULL); -- signal_set(&svrdirev, SIGHUP, svrreopen, NULL); -- signal_add(&svrdirev, NULL); -+ rootdirev = evsignal_new(evbase, SIGUSR1, dirscancb, &icq); -+ if (rootdirev == NULL) -+ errx(1, "Failed to create SIGUSR1 event."); -+ evsignal_add(rootdirev, NULL); -+ clntdirev = evsignal_new(evbase, SIGUSR2, clntscancb, &icq); -+ if (clntdirev == NULL) -+ errx(1, "Failed to create SIGUSR2 event."); -+ evsignal_add(clntdirev, NULL); -+ svrdirev = evsignal_new(evbase, SIGHUP, svrreopen, NULL); -+ if (svrdirev == NULL) -+ errx(1, "Failed to create SIGHUP event."); -+ evsignal_add(svrdirev, NULL); - if ( wd >= 0) { -- event_set(&inotifyev, inotify_fd, EV_READ, dirscancb, &icq); -- event_add(&inotifyev, NULL); -+ inotifyev = event_new(evbase, inotify_fd, -+ EV_READ | EV_PERSIST, dirscancb, &icq); -+ if (inotifyev == NULL) -+ errx(1, "Failed to create inotify read event."); -+ event_add(inotifyev, NULL); - } - - /* Fetch current state */ - /* (Delay till start of event_dispatch to avoid possibly losing - * a SIGUSR1 between here and the call to event_dispatch().) */ -- evtimer_set(&initialize, dirscancb, &icq); -- evtimer_add(&initialize, &now); -+ initialize = evtimer_new(evbase, dirscancb, &icq); -+ if (initialize == NULL) -+ errx(1, "Failed to create initialize event."); -+ evtimer_add(initialize, &now); - } - - if (nfsdret != 0 && wd < 0) -@@ -419,15 +455,60 @@ main(int argc, char **argv) - - daemon_ready(); - -- if (event_dispatch() < 0) -+ if (event_base_dispatch(evbase) < 0) - xlog_err("main: event_dispatch returns errno %d (%s)", - errno, strerror(errno)); -- /* NOTREACHED */ -+ -+ nfs4_term_name_mapping(); -+ nfsdclose(); -+ -+ if (inotifyev) -+ event_free(inotifyev); -+ if (inotify_fd != -1) -+ close(inotify_fd); -+ -+ if (initialize) -+ event_free(initialize); -+ if (rootdirev) -+ event_free(rootdirev); -+ if (clntdirev) -+ event_free(clntdirev); -+ if (svrdirev) -+ event_free(svrdirev); -+ event_base_free(evbase); -+ - return 1; - } - - static void --dirscancb(int UNUSED(fd), short UNUSED(which), void *data) -+flush_inotify(int fd) -+{ -+ while (true) { -+ char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); -+ const struct inotify_event *ev; -+ ssize_t len; -+ char *ptr; -+ -+ len = read(fd, buf, sizeof(buf)); -+ if (len == -1 && errno == EINTR) -+ continue; -+ -+ if (len <= 0) -+ break; -+ -+ for (ptr = buf; ptr < buf + len; -+ ptr += sizeof(struct inotify_event) + ev->len) { -+ -+ ev = (const struct inotify_event *)ptr; -+ if (verbose > 2) -+ xlog_warn("pipefs inotify: wd=%i, mask=0x%08x, len=%i, name=%s", -+ ev->wd, ev->mask, ev->len, ev->len ? ev->name : ""); -+ } -+ } -+} -+ -+static void -+dirscancb(int fd, short UNUSED(which), void *data) - { - int nent, i; - struct dirent **ents; -@@ -435,6 +516,13 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data) - char path[PATH_MAX+256]; /* + sizeof(d_name) */ - struct idmap_clientq *icq = data; - -+ if (fd != -1) -+ flush_inotify(fd); -+ -+ TAILQ_FOREACH(ic, icq, ic_next) { -+ ic->ic_scanned = 0; -+ } -+ - nent = scandir(pipefsdir, &ents, NULL, alphasort); - if (nent == -1) { - xlog_warn("dirscancb: scandir(%s): %s", pipefsdir, strerror(errno)); -@@ -468,15 +556,15 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data) - strlcat(path, "/idmap", sizeof(path)); - strlcpy(ic->ic_path, path, sizeof(ic->ic_path)); - -- if (verbose > 0) -- xlog_warn("New client: %s", ic->ic_clid); -- - if (nfsopen(ic) == -1) { - close(ic->ic_dirfd); - free(ic); - goto out; - } - -+ if (verbose > 2) -+ xlog_warn("New client: %s", ic->ic_clid); -+ - ic->ic_id = "Client"; - - TAILQ_INSERT_TAIL(icq, ic, ic_next); -@@ -490,17 +578,19 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data) - while(ic != NULL) { - nextic=TAILQ_NEXT(ic, ic_next); - if (!ic->ic_scanned) { -- event_del(&ic->ic_event); -- close(ic->ic_fd); -- close(ic->ic_dirfd); -+ if (ic->ic_event) -+ event_free(ic->ic_event); -+ if (ic->ic_fd != -1) -+ close(ic->ic_fd); -+ if (ic->ic_dirfd != -1) -+ close(ic->ic_dirfd); - TAILQ_REMOVE(icq, ic, ic_next); -- if (verbose > 0) { -+ if (verbose > 2) { - xlog_warn("Stale client: %s", ic->ic_clid); - xlog_warn("\t-> closed %s", ic->ic_path); - } - free(ic); -- } else -- ic->ic_scanned = 0; -+ } - ic = nextic; - } - -@@ -546,7 +636,7 @@ nfsdcb(int UNUSED(fd), short which, void *data) - unsigned long tmp; - - if (which != EV_READ) -- goto out; -+ return; - - len = read(ic->ic_fd, buf, sizeof(buf)); - if (len == 0) -@@ -569,13 +659,13 @@ nfsdcb(int UNUSED(fd), short which, void *data) - /* Authentication name -- ignored for now*/ - if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) { - xlog_warn("nfsdcb: bad authentication name in upcall\n"); -- goto out; -+ return; - } - if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) { - xlog_warn("nfsdcb: bad type in upcall\n"); -- goto out; -+ return; - } -- if (verbose > 0) -+ if (verbose > 2) - xlog_warn("nfsdcb: authbuf=%s authtype=%s", - authbuf, typebuf); - -@@ -587,26 +677,26 @@ nfsdcb(int UNUSED(fd), short which, void *data) - im.im_conv = IDMAP_CONV_NAMETOID; - if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) { - xlog_warn("nfsdcb: bad name in upcall\n"); -- goto out; -+ return; - } - break; - case IC_IDNAME: - im.im_conv = IDMAP_CONV_IDTONAME; - if (getfield(&bp, buf1, sizeof(buf1)) == -1) { - xlog_warn("nfsdcb: bad id in upcall\n"); -- goto out; -+ return; - } - tmp = strtoul(buf1, (char **)NULL, 10); - im.im_id = (u_int32_t)tmp; - if ((tmp == ULONG_MAX && errno == ERANGE) - || (unsigned long)im.im_id != tmp) { - xlog_warn("nfsdcb: id '%s' too big!\n", buf1); -- goto out; -+ return; - } - break; - default: - xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which); -- goto out; -+ return; - } - - imconv(ic, &im); -@@ -667,7 +757,7 @@ nfsdcb(int UNUSED(fd), short which, void *data) - break; - default: - xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which); -- goto out; -+ return; - } - - bsiz = sizeof(buf) - bsiz; -@@ -675,9 +765,6 @@ nfsdcb(int UNUSED(fd), short which, void *data) - if (atomicio((void*)write, ic->ic_fd, buf, bsiz) != bsiz) - xlog_warn("nfsdcb: write(%s) failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); -- --out: -- event_add(&ic->ic_event, NULL); - } - - static void -@@ -721,14 +808,12 @@ nfscb(int UNUSED(fd), short which, void *data) - struct idmap_msg im; - - if (which != EV_READ) -- goto out; -+ return; - - if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) { - if (verbose > 0) - xlog_warn("nfscb: read(%s): %s", ic->ic_path, strerror(errno)); -- if (errno == EPIPE) -- return; -- goto out; -+ return; - } - - imconv(ic, &im); -@@ -742,8 +827,19 @@ nfscb(int UNUSED(fd), short which, void *data) - - if (atomicio((void*)write, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) - xlog_warn("nfscb: write(%s): %s", ic->ic_path, strerror(errno)); --out: -- event_add(&ic->ic_event, NULL); -+} -+ -+static void -+nfsdclose_one(struct idmap_client *ic) -+{ -+ if (ic->ic_event) { -+ event_free(ic->ic_event); -+ ic->ic_event = NULL; -+ } -+ if (ic->ic_fd != -1) { -+ close(ic->ic_fd); -+ ic->ic_fd = -1; -+ } - } - - static void -@@ -751,18 +847,22 @@ nfsdreopen_one(struct idmap_client *ic) - { - int fd; - -- if (verbose > 0) -+ if (verbose > 2) - xlog_warn("ReOpening %s", ic->ic_path); - - if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) { -- if ((event_initialized(&ic->ic_event))) -- event_del(&ic->ic_event); -- if (ic->ic_fd != -1) -- close(ic->ic_fd); -+ nfsdclose_one(ic); - -- ic->ic_event.ev_fd = ic->ic_fd = fd; -- event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic); -- event_add(&ic->ic_event, NULL); -+ ic->ic_fd = fd; -+ ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfsdcb, ic); -+ if (ic->ic_event == NULL) { -+ xlog_warn("nfsdreopen: Failed to create event for '%s'", -+ ic->ic_path); -+ close(ic->ic_fd); -+ ic->ic_fd = -1; -+ return; -+ } -+ event_add(ic->ic_event, NULL); - } else { - xlog_warn("nfsdreopen: Opening '%s' failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); -@@ -784,6 +884,13 @@ nfsdopen(void) - nfsdopenone(&nfsd_ic[IC_IDNAME]) == 0) ? 0 : -1); - } - -+static void -+nfsdclose(void) -+{ -+ nfsdclose_one(&nfsd_ic[IC_NAMEID]); -+ nfsdclose_one(&nfsd_ic[IC_IDNAME]); -+} -+ - static int - nfsdopenone(struct idmap_client *ic) - { -@@ -795,10 +902,18 @@ nfsdopenone(struct idmap_client *ic) - return (-1); - } - -- event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic); -- event_add(&ic->ic_event, NULL); -+ ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfsdcb, ic); -+ if (ic->ic_event == NULL) { -+ if (verbose > 0) -+ xlog_warn("nfsdopenone: Create event for %s failed", -+ ic->ic_path); -+ close(ic->ic_fd); -+ ic->ic_fd = -1; -+ return (-1); -+ } -+ event_add(ic->ic_event, NULL); - -- if (verbose > 0) -+ if (verbose > 2) - xlog_warn("Opened %s", ic->ic_path); - - return (0); -@@ -808,25 +923,35 @@ static int - nfsopen(struct idmap_client *ic) - { - if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) { -- switch (errno) { -- case ENOENT: -- fcntl(ic->ic_dirfd, F_SETSIG, SIGUSR2); -- fcntl(ic->ic_dirfd, F_NOTIFY, -- DN_CREATE | DN_DELETE | DN_MULTISHOT); -- break; -- default: -- xlog_warn("nfsopen: open(%s): %s", ic->ic_path, strerror(errno)); -- return (-1); -+ if (errno == ENOENT) { -+ char *slash; -+ -+ slash = strrchr(ic->ic_path, '/'); -+ if (!slash) -+ return -1; -+ *slash = 0; -+ inotify_add_watch(inotify_fd, ic->ic_path, IN_CREATE | IN_ONLYDIR | IN_ONESHOT); -+ *slash = '/'; -+ if (verbose > 2) -+ xlog_warn("Path %s not available. waiting...", ic->ic_path); -+ return -1; - } -- } else { -- event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); -- event_add(&ic->ic_event, NULL); -- fcntl(ic->ic_dirfd, F_NOTIFY, 0); -- fcntl(ic->ic_dirfd, F_SETSIG, 0); -- if (verbose > 0) -- xlog_warn("Opened %s", ic->ic_path); -+ -+ xlog_warn("nfsopen: open(%s): %s", ic->ic_path, strerror(errno)); -+ return (-1); - } - -+ ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfscb, ic); -+ if (ic->ic_event == NULL) { -+ xlog_warn("nfsopen: Create event for %s failed", ic->ic_path); -+ close(ic->ic_fd); -+ ic->ic_fd = -1; -+ return -1; -+ } -+ event_add(ic->ic_event, NULL); -+ if (verbose > 2) -+ xlog_warn("Opened %s", ic->ic_path); -+ - return (0); - } - -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 6ac913d..d9c0b51 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -1268,14 +1268,14 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) - int - nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *version) - { -- char *version_key, *version_val, *cptr; -+ char *version_key, *version_val = NULL, *cptr; - int i, found = 0; - - version->v_mode = V_DEFAULT; - - for (i = 0; nfs_version_opttbl[i]; i++) { - if (po_contains_prefix(options, nfs_version_opttbl[i], -- &version_key) == PO_FOUND) { -+ &version_key) == PO_FOUND) { - found++; - break; - } -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 901f995..91a976b 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -1094,9 +1094,7 @@ static int nfsmount_fg(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - --#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" - if (errno == EBUSY && is_mountpoint(mi->node)) { --#pragma GCC diagnostic warning "-Wdiscarded-qualifiers" - /* - * EBUSY can happen when mounting a filesystem that - * is already mounted or when the context= are -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 6cba288..ea74067 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -57,7 +57,7 @@ enum nfsd_fsid { - }; - - #undef is_mountpoint --static int is_mountpoint(char *path) -+static int is_mountpoint(const char *path) - { - return check_is_mountpoint(path, nfsd_path_lstat); - } -diff --git a/utils/nfsdcld/cld-internal.h b/utils/nfsdcld/cld-internal.h -index cc283da..3576515 100644 ---- a/utils/nfsdcld/cld-internal.h -+++ b/utils/nfsdcld/cld-internal.h -@@ -26,7 +26,7 @@ - - struct cld_client { - int cl_fd; -- struct event cl_event; -+ struct event *cl_event; - union { - struct cld_msg cl_msg; - #if UPCALL_VERSION >= 2 -diff --git a/utils/nfsdcld/legacy.c b/utils/nfsdcld/legacy.c -index 3c6bea6..b89374c 100644 ---- a/utils/nfsdcld/legacy.c -+++ b/utils/nfsdcld/legacy.c -@@ -48,35 +48,28 @@ legacy_load_clients_from_recdir(int *num_records) - int fd; - DIR *v4recovery; - struct dirent *entry; -- char recdirname[PATH_MAX]; -+ char recdirname[PATH_MAX+1]; - char buf[NFS4_OPAQUE_LIMIT]; -- struct stat st; - char *nl; -+ ssize_t n; - - fd = open(NFSD_RECDIR_FILE, O_RDONLY); - if (fd < 0) { - xlog(D_GENERAL, "Unable to open %s: %m", NFSD_RECDIR_FILE); - return; - } -- if (read(fd, recdirname, PATH_MAX) < 0) { -+ n = read(fd, recdirname, PATH_MAX); -+ close(fd); -+ if (n < 0) { - xlog(D_GENERAL, "Unable to read from %s: %m", NFSD_RECDIR_FILE); - return; - } -- close(fd); - /* the output from the proc file isn't null-terminated */ -+ recdirname[PATH_MAX] = '\0'; - nl = strchr(recdirname, '\n'); - if (!nl) - return; - *nl = '\0'; -- if (stat(recdirname, &st) < 0) { -- xlog(D_GENERAL, "Unable to stat %s: %d", recdirname, errno); -- return; -- } -- if (!S_ISDIR(st.st_mode)) { -- xlog(D_GENERAL, "%s is not a directory: mode=0%o", recdirname -- , st.st_mode); -- return; -- } - v4recovery = opendir(recdirname); - if (!v4recovery) - return; -@@ -123,35 +116,28 @@ legacy_clear_recdir(void) - int fd; - DIR *v4recovery; - struct dirent *entry; -- char recdirname[PATH_MAX]; -+ char recdirname[PATH_MAX+1]; - char dirname[PATH_MAX]; -- struct stat st; - char *nl; -+ ssize_t n; - - fd = open(NFSD_RECDIR_FILE, O_RDONLY); - if (fd < 0) { - xlog(D_GENERAL, "Unable to open %s: %m", NFSD_RECDIR_FILE); - return; - } -- if (read(fd, recdirname, PATH_MAX) < 0) { -+ n = read(fd, recdirname, PATH_MAX); -+ close(fd); -+ if (n < 0) { - xlog(D_GENERAL, "Unable to read from %s: %m", NFSD_RECDIR_FILE); - return; - } -- close(fd); - /* the output from the proc file isn't null-terminated */ -+ recdirname[PATH_MAX] = '\0'; - nl = strchr(recdirname, '\n'); - if (!nl) - return; - *nl = '\0'; -- if (stat(recdirname, &st) < 0) { -- xlog(D_GENERAL, "Unable to stat %s: %d", recdirname, errno); -- return; -- } -- if (!S_ISDIR(st.st_mode)) { -- xlog(D_GENERAL, "%s is not a directory: mode=0%o", recdirname -- , st.st_mode); -- return; -- } - v4recovery = opendir(recdirname); - if (!v4recovery) - return; -diff --git a/utils/nfsdcld/nfsdcld.c b/utils/nfsdcld/nfsdcld.c -index be65562..636c398 100644 ---- a/utils/nfsdcld/nfsdcld.c -+++ b/utils/nfsdcld/nfsdcld.c -@@ -24,9 +24,10 @@ - #endif /* HAVE_CONFIG_H */ - - #include --#include -+#include - #include - #include -+#include - #include - #include - #include -@@ -66,8 +67,10 @@ - static char pipefs_dir[PATH_MAX] = DEFAULT_PIPEFS_DIR; - static char pipepath[PATH_MAX]; - static int inotify_fd = -1; --static struct event pipedir_event; -+static struct event *pipedir_event; -+static struct event_base *evbase; - static bool old_kernel = false; -+static bool signal_received = false; - - uint64_t current_epoch; - uint64_t recovery_epoch; -@@ -88,6 +91,19 @@ static struct option longopts[] = - /* forward declarations */ - static void cldcb(int UNUSED(fd), short which, void *data); - -+static void -+sig_die(int signal) -+{ -+ if (signal_received) { -+ xlog(D_GENERAL, "forced exiting on signal %d\n", signal); -+ exit(0); -+ } -+ -+ signal_received = true; -+ xlog(D_GENERAL, "exiting on signal %d\n", signal); -+ event_base_loopexit(evbase, NULL); -+} -+ - static void - usage(char *progname) - { -@@ -141,6 +157,7 @@ static int - cld_pipe_open(struct cld_client *clnt) - { - int fd; -+ struct event *ev; - - xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath); - fd = open(pipepath, O_RDWR, 0); -@@ -149,13 +166,22 @@ cld_pipe_open(struct cld_client *clnt) - return -errno; - } - -- if (event_initialized(&clnt->cl_event)) -- event_del(&clnt->cl_event); -+ ev = event_new(evbase, fd, EV_READ, cldcb, clnt); -+ if (ev == NULL) { -+ xlog(D_GENERAL, "%s: failed to create event for %s", __func__, pipepath); -+ close(fd); -+ return -ENOMEM; -+ } -+ -+ if (clnt->cl_event && event_initialized(clnt->cl_event)) { -+ event_del(clnt->cl_event); -+ event_free(clnt->cl_event); -+ } - if (clnt->cl_fd >= 0) - close(clnt->cl_fd); - - clnt->cl_fd = fd; -- event_set(&clnt->cl_event, clnt->cl_fd, EV_READ, cldcb, clnt); -+ clnt->cl_event = ev; - /* event_add is done by the caller */ - return 0; - } -@@ -208,7 +234,7 @@ cld_inotify_cb(int UNUSED(fd), short which, void *data) - switch (ret) { - case 0: - /* readd the event for the cl_event pipe */ -- event_add(&clnt->cl_event, NULL); -+ event_add(clnt->cl_event, NULL); - break; - case -ENOENT: - /* pipe must have disappeared, wait for it to come back */ -@@ -221,7 +247,7 @@ cld_inotify_cb(int UNUSED(fd), short which, void *data) - } - - out: -- event_add(&pipedir_event, NULL); -+ event_add(pipedir_event, NULL); - free(dirc); - } - -@@ -252,11 +278,12 @@ cld_inotify_setup(void) - xlog_err("%s: inotify_add_watch failed: %m", __func__); - ret = -errno; - goto out_err; -- } -+ } else -+ ret = 0; - - out_free: - free(dirc); -- return 0; -+ return ret; - out_err: - close(inotify_fd); - goto out_free; -@@ -286,7 +313,7 @@ cld_pipe_init(struct cld_client *clnt) - switch (ret) { - case 0: - /* add the event and we're good to go */ -- event_add(&clnt->cl_event, NULL); -+ event_add(clnt->cl_event, NULL); - break; - case -ENOENT: - /* ignore this error -- cld_inotify_cb will handle it */ -@@ -299,8 +326,12 @@ cld_pipe_init(struct cld_client *clnt) - } - - /* set event for inotify read */ -- event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt); -- event_add(&pipedir_event, NULL); -+ pipedir_event = event_new(evbase, inotify_fd, EV_READ, cld_inotify_cb, clnt); -+ if (pipedir_event == NULL) { -+ close(inotify_fd); -+ return -ENOMEM; -+ } -+ event_add(pipedir_event, NULL); - out: - return ret; - } -@@ -331,6 +362,7 @@ cld_check_grace_period(void) - if (read(fd, &c, 1) < 0) { - xlog(L_WARNING, "Unable to read from %s: %m", - NFSD_END_GRACE_FILE); -+ close(fd); - return 1; - } - close(fd); -@@ -737,7 +769,7 @@ cldcb(int UNUSED(fd), short which, void *data) - cld_not_implemented(clnt); - } - out: -- event_add(&clnt->cl_event, NULL); -+ event_add(clnt->cl_event, NULL); - } - - int -@@ -762,7 +794,11 @@ main(int argc, char **argv) - return 1; - } - -- event_init(); -+ evbase = event_base_new(); -+ if (evbase == NULL) { -+ fprintf(stderr, "%s: unable to allocate event base.\n", argv[0]); -+ return 1; -+ } - xlog_syslog(0); - xlog_stderr(1); - -@@ -795,6 +831,7 @@ main(int argc, char **argv) - break; - default: - usage(progname); -+ free(progname); - return 0; - } - } -@@ -859,14 +896,27 @@ main(int argc, char **argv) - if (rc) - goto out; - -+ signal(SIGINT, sig_die); -+ signal(SIGTERM, sig_die); -+ - xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__); -- rc = event_dispatch(); -+ rc = event_base_dispatch(evbase); - if (rc < 0) - xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__); - -- close(clnt.cl_fd); -- close(inotify_fd); - out: -+ if (clnt.cl_event) -+ event_free(clnt.cl_event); -+ if (clnt.cl_fd != -1) -+ close(clnt.cl_fd); -+ if (pipedir_event) -+ event_free(pipedir_event); -+ if (inotify_fd != -1) -+ close(inotify_fd); -+ -+ event_base_free(evbase); -+ sqlite_shutdown(); -+ - free(progname); - return rc; - } -diff --git a/utils/nfsdcld/sqlite.c b/utils/nfsdcld/sqlite.c -index 6666c86..03016fb 100644 ---- a/utils/nfsdcld/sqlite.c -+++ b/utils/nfsdcld/sqlite.c -@@ -48,7 +48,6 @@ - - #include - #include --#include - #include - #include - #include -@@ -380,7 +379,7 @@ sqlite_maindb_init_v4(void) - &err); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "Unable to begin transaction: %s", err); -- return ret; -+ goto out; - } - - /* -@@ -831,7 +830,6 @@ sqlite_prepare_dbh(const char *topdir) - switch (ret) { - case CLD_SQLITE_LATEST_SCHEMA_VERSION: - /* DB is already set up. Do nothing */ -- ret = 0; - break; - case 3: - /* Old DB -- update to new schema */ -@@ -868,6 +866,8 @@ sqlite_prepare_dbh(const char *topdir) - } - - ret = sqlite_startup_query_grace(); -+ if (ret) -+ goto out_close; - - ret = sqlite_query_first_time(&first_time); - if (ret) -@@ -1330,20 +1330,26 @@ sqlite_iterate_recovery(int (*cb)(struct cld_client *clnt), struct cld_client *c - } - - while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) { -+ const void *id; -+ int id_len; -+ -+ id = sqlite3_column_blob(stmt, 0); -+ id_len = sqlite3_column_bytes(stmt, 0); -+ if (id_len > NFS4_OPAQUE_LIMIT) -+ id_len = NFS4_OPAQUE_LIMIT; -+ - memset(&cmsg->cm_u, 0, sizeof(cmsg->cm_u)); - #if UPCALL_VERSION >= 2 -- memcpy(&cmsg->cm_u.cm_clntinfo.cc_name.cn_id, -- sqlite3_column_blob(stmt, 0), NFS4_OPAQUE_LIMIT); -- cmsg->cm_u.cm_clntinfo.cc_name.cn_len = sqlite3_column_bytes(stmt, 0); -+ memcpy(&cmsg->cm_u.cm_clntinfo.cc_name.cn_id, id, id_len); -+ cmsg->cm_u.cm_clntinfo.cc_name.cn_len = id_len; - if (sqlite3_column_bytes(stmt, 1) > 0) { - memcpy(&cmsg->cm_u.cm_clntinfo.cc_princhash.cp_data, - sqlite3_column_blob(stmt, 1), SHA256_DIGEST_SIZE); - cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = sqlite3_column_bytes(stmt, 1); - } - #else -- memcpy(&cmsg->cm_u.cm_name.cn_id, sqlite3_column_blob(stmt, 0), -- NFS4_OPAQUE_LIMIT); -- cmsg->cm_u.cm_name.cn_len = sqlite3_column_bytes(stmt, 0); -+ memcpy(&cmsg->cm_u.cm_name.cn_id, id, id_len); -+ cmsg->cm_u.cm_name.cn_len = id_len; - #endif - cb(clnt); - } -@@ -1404,3 +1410,18 @@ sqlite_first_time_done(void) - sqlite3_free(err); - return ret; - } -+ -+/* -+ * Closes all sqlite3 resources and shuts down the library. -+ * -+ */ -+void -+sqlite_shutdown(void) -+{ -+ if (dbh != NULL) { -+ sqlite3_close(dbh); -+ dbh = NULL; -+ } -+ -+ sqlite3_shutdown(); -+} -diff --git a/utils/nfsdcld/sqlite.h b/utils/nfsdcld/sqlite.h -index 0a26ad6..044236c 100644 ---- a/utils/nfsdcld/sqlite.h -+++ b/utils/nfsdcld/sqlite.h -@@ -34,4 +34,5 @@ int sqlite_iterate_recovery(int (*cb)(struct cld_client *clnt), struct cld_clien - int sqlite_delete_cltrack_records(void); - int sqlite_first_time_done(void); - -+void sqlite_shutdown(void); - #endif /* _SQLITE_H */ -diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c -index 2801201..f79aebb 100644 ---- a/utils/nfsdcltrack/sqlite.c -+++ b/utils/nfsdcltrack/sqlite.c -@@ -40,7 +40,7 @@ - - #include - #include --#include -+#include - #include - #include - #include diff --git a/nfs-utils-2.5.3-rc1.patch b/nfs-utils-2.5.3-rc1.patch deleted file mode 100644 index 899393f..0000000 --- a/nfs-utils-2.5.3-rc1.patch +++ /dev/null @@ -1,301 +0,0 @@ -diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c -index 8efbfcd..65e53c1 100644 ---- a/support/misc/nfsd_path.c -+++ b/support/misc/nfsd_path.c -@@ -110,7 +110,7 @@ nfsd_setup_workqueue(void) - - if (!rootdir) - return; --printf("rootdir %s\n", rootdir); -+ - nfsd_wq = xthread_workqueue_alloc(); - if (!nfsd_wq) - return; -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 3d13610..a4ea067 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -52,10 +52,14 @@ - #include - #include - #include -+#include - - #include "conffile.h" - #include "xlog.h" - -+#define CONF_FILE_EXT ".conf" -+#define CONF_FILE_EXT_LEN ((int) (sizeof(CONF_FILE_EXT) - 1)) -+ - #pragma GCC visibility push(hidden) - - static void conf_load_defaults(void); -@@ -456,7 +460,7 @@ conf_parse_line(int trans, char *line, const char *filename, int lineno, char ** - free(subconf); - } else { - /* XXX Perhaps should we not ignore errors? */ -- conf_set(trans, *section, *subsection, line, val, 0, 0); -+ conf_set(trans, *section, *subsection, line, val, 1, 0); - } - } - -@@ -577,6 +581,30 @@ static void conf_free_bindings(void) - } - } - -+static int -+conf_load_files(int trans, const char *conf_file) -+{ -+ char *conf_data; -+ char *section = NULL; -+ char *subsection = NULL; -+ -+ conf_data = conf_readfile(conf_file); -+ if (conf_data == NULL) -+ return 1; -+ -+ /* Load default configuration values. */ -+ conf_load_defaults(); -+ -+ /* Parse config contents into the transaction queue */ -+ conf_parse(trans, conf_data, §ion, &subsection, conf_file); -+ if (section) -+ free(section); -+ if (subsection) -+ free(subsection); -+ free(conf_data); -+ -+ return 0; -+} - /* Open the config file and map it into our address space, then parse it. */ - static int - conf_load_file(const char *conf_file) -@@ -609,18 +637,129 @@ conf_load_file(const char *conf_file) - return 0; - } - -+static void -+conf_init_dir(const char *conf_file) -+{ -+ struct dirent **namelist = NULL; -+ char *dname, fname[PATH_MAX], *cname; -+ int n = 0, nfiles = 0, i, fname_len, dname_len; -+ int trans, rv, path_len; -+ -+ dname = malloc(strlen(conf_file) + 3); -+ if (dname == NULL) { -+ xlog(L_WARNING, "conf_init_dir: malloc: %s", strerror(errno)); -+ return; -+ } -+ sprintf(dname, "%s.d", conf_file); -+ -+ n = scandir(dname, &namelist, NULL, versionsort); -+ if (n < 0) { -+ if (errno != ENOENT) { -+ xlog(L_WARNING, "conf_init_dir: scandir %s: %s", -+ dname, strerror(errno)); -+ } -+ free(dname); -+ return; -+ } else if (n == 0) { -+ free(dname); -+ return; -+ } -+ -+ trans = conf_begin(); -+ dname_len = strlen(dname); -+ for (i = 0; i < n; i++ ) { -+ struct dirent *d = namelist[i]; -+ -+ switch (d->d_type) { -+ case DT_UNKNOWN: -+ case DT_REG: -+ case DT_LNK: -+ break; -+ default: -+ continue; -+ } -+ if (*d->d_name == '.') -+ continue; -+ -+ fname_len = strlen(d->d_name); -+ path_len = (fname_len + dname_len); -+ if (!fname_len || path_len > PATH_MAX) { -+ xlog(L_WARNING, "conf_init_dir: Too long file name: %s in %s", -+ d->d_name, dname); -+ continue; -+ } -+ -+ /* -+ * Check the naming of the file. Only process files -+ * that end with CONF_FILE_EXT -+ */ -+ if (fname_len <= CONF_FILE_EXT_LEN) { -+ xlog(D_GENERAL, "conf_init_dir: %s: name too short", -+ d->d_name); -+ continue; -+ } -+ cname = (d->d_name + (fname_len - CONF_FILE_EXT_LEN)); -+ if (strcmp(cname, CONF_FILE_EXT) != 0) { -+ xlog(D_GENERAL, "conf_init_dir: %s: invalid file extension", -+ d->d_name); -+ continue; -+ } -+ -+ rv = snprintf(fname, PATH_MAX, "%s/%s", dname, d->d_name); -+ if (rv < path_len) { -+ xlog(L_WARNING, "conf_init_dir: file name: %s/%s too short", -+ d->d_name, dname); -+ continue; -+ } -+ -+ if (conf_load_files(trans, fname)) -+ continue; -+ nfiles++; -+ } -+ -+ if (nfiles) { -+ /* Apply the configuration values */ -+ conf_end(trans, 1); -+ } -+ for (i = 0; i < n; i++) -+ free(namelist[i]); -+ free(namelist); -+ free(dname); -+ -+ return; -+} -+ - int - conf_init_file(const char *conf_file) - { - unsigned int i; -+ int ret; - - for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) - LIST_INIT (&conf_bindings[i]); - - TAILQ_INIT (&conf_trans_queue); - -- if (conf_file == NULL) conf_file=NFS_CONFFILE; -- return conf_load_file(conf_file); -+ if (conf_file == NULL) -+ conf_file=NFS_CONFFILE; -+ -+ /* -+ * First parse the give config file -+ * then parse the config.conf.d directory -+ * (if it exists) -+ * -+ */ -+ ret = conf_load_file(conf_file); -+ -+ /* -+ * When the same variable is set in both files -+ * the conf.d file will override the config file. -+ * This allows automated admin systems to -+ * have the final say. -+ */ -+ conf_init_dir(conf_file); -+ -+ return ret; - } - - /* -diff --git a/systemd/nfs-v4client.target b/systemd/nfs-v4client.target -new file mode 100644 -index 0000000..3d1064e ---- /dev/null -+++ b/systemd/nfs-v4client.target -@@ -0,0 +1,12 @@ -+[Unit] -+Description=NFS client services -+Before=remote-fs-pre.target -+Wants=remote-fs-pre.target -+ -+# GSS services dependencies and ordering -+Wants=auth-rpcgss-module.service -+After=rpc-gssd.service rpc-svcgssd.service gssproxy.service -+ -+[Install] -+WantedBy=multi-user.target -+WantedBy=remote-fs.target -diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man -index 3f1c726..16e0ec4 100644 ---- a/systemd/nfs.conf.man -+++ b/systemd/nfs.conf.man -@@ -265,7 +265,15 @@ Only - is recognized. - - .SH FILES -+.TP 10n - .I /etc/nfs.conf -+Default NFS client configuration file -+.TP 10n -+.I /etc/nfs.conf.d -+When this directory exists and files ending -+with ".conf" exist, those files will be -+used to set configuration variables. These -+files will override variables set in /etc/nfs.conf - .SH SEE ALSO - .BR nfsdcltrack (8), - .BR rpc.nfsd (8), -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 25e92a1..23876fc 100755 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -378,7 +378,10 @@ class DeviceData: - print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) - elif vers == '4': - for op in Nfsv4ops: -- print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ try: -+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ except KeyError: -+ continue - else: - print('\tnot implemented for version %d' % vers) - print() -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 9d5e575..9fcae0b 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -176,10 +176,10 @@ main(int argc, char **argv) - xlog(L_ERROR, "-r and -u are incompatible"); - return 1; - } --printf("point 1\n"); -+ - if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) - return 1; --printf("point 2\n"); -+ - if (optind == argc && ! f_all) { - if (force_flush) { - cache_flush(1); -@@ -193,7 +193,6 @@ printf("point 2\n"); - return 0; - } - } --printf("point 3\n"); - - /* - * Serialize things as best we can -diff --git a/utils/mount/nfsmount.conf.man b/utils/mount/nfsmount.conf.man -index 3aa3456..4f8f351 100644 ---- a/utils/mount/nfsmount.conf.man -+++ b/utils/mount/nfsmount.conf.man -@@ -88,6 +88,13 @@ the background (i.e. done asynchronously). - .TP 10n - .I /etc/nfsmount.conf - Default NFS mount configuration file -+.TP 10n -+.I /etc/nfsmount.conf.d -+When this directory exists and files ending -+with ".conf" exist, those files will be -+used to set configuration variables. These -+files will override variables set -+in /etc/nfsmount.conf - .PD - .SH SEE ALSO - .BR nfs (5), diff --git a/nfs-utils-2.5.3-rc4.patch b/nfs-utils-2.5.3-rc4.patch deleted file mode 100644 index 9d6ad60..0000000 --- a/nfs-utils-2.5.3-rc4.patch +++ /dev/null @@ -1,1117 +0,0 @@ -diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c -index 8efbfcd..65e53c1 100644 ---- a/support/misc/nfsd_path.c -+++ b/support/misc/nfsd_path.c -@@ -110,7 +110,7 @@ nfsd_setup_workqueue(void) - - if (!rootdir) - return; --printf("rootdir %s\n", rootdir); -+ - nfsd_wq = xthread_workqueue_alloc(); - if (!nfsd_wq) - return; -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 3d13610..a4ea067 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -52,10 +52,14 @@ - #include - #include - #include -+#include - - #include "conffile.h" - #include "xlog.h" - -+#define CONF_FILE_EXT ".conf" -+#define CONF_FILE_EXT_LEN ((int) (sizeof(CONF_FILE_EXT) - 1)) -+ - #pragma GCC visibility push(hidden) - - static void conf_load_defaults(void); -@@ -456,7 +460,7 @@ conf_parse_line(int trans, char *line, const char *filename, int lineno, char ** - free(subconf); - } else { - /* XXX Perhaps should we not ignore errors? */ -- conf_set(trans, *section, *subsection, line, val, 0, 0); -+ conf_set(trans, *section, *subsection, line, val, 1, 0); - } - } - -@@ -577,6 +581,30 @@ static void conf_free_bindings(void) - } - } - -+static int -+conf_load_files(int trans, const char *conf_file) -+{ -+ char *conf_data; -+ char *section = NULL; -+ char *subsection = NULL; -+ -+ conf_data = conf_readfile(conf_file); -+ if (conf_data == NULL) -+ return 1; -+ -+ /* Load default configuration values. */ -+ conf_load_defaults(); -+ -+ /* Parse config contents into the transaction queue */ -+ conf_parse(trans, conf_data, §ion, &subsection, conf_file); -+ if (section) -+ free(section); -+ if (subsection) -+ free(subsection); -+ free(conf_data); -+ -+ return 0; -+} - /* Open the config file and map it into our address space, then parse it. */ - static int - conf_load_file(const char *conf_file) -@@ -609,18 +637,129 @@ conf_load_file(const char *conf_file) - return 0; - } - -+static void -+conf_init_dir(const char *conf_file) -+{ -+ struct dirent **namelist = NULL; -+ char *dname, fname[PATH_MAX], *cname; -+ int n = 0, nfiles = 0, i, fname_len, dname_len; -+ int trans, rv, path_len; -+ -+ dname = malloc(strlen(conf_file) + 3); -+ if (dname == NULL) { -+ xlog(L_WARNING, "conf_init_dir: malloc: %s", strerror(errno)); -+ return; -+ } -+ sprintf(dname, "%s.d", conf_file); -+ -+ n = scandir(dname, &namelist, NULL, versionsort); -+ if (n < 0) { -+ if (errno != ENOENT) { -+ xlog(L_WARNING, "conf_init_dir: scandir %s: %s", -+ dname, strerror(errno)); -+ } -+ free(dname); -+ return; -+ } else if (n == 0) { -+ free(dname); -+ return; -+ } -+ -+ trans = conf_begin(); -+ dname_len = strlen(dname); -+ for (i = 0; i < n; i++ ) { -+ struct dirent *d = namelist[i]; -+ -+ switch (d->d_type) { -+ case DT_UNKNOWN: -+ case DT_REG: -+ case DT_LNK: -+ break; -+ default: -+ continue; -+ } -+ if (*d->d_name == '.') -+ continue; -+ -+ fname_len = strlen(d->d_name); -+ path_len = (fname_len + dname_len); -+ if (!fname_len || path_len > PATH_MAX) { -+ xlog(L_WARNING, "conf_init_dir: Too long file name: %s in %s", -+ d->d_name, dname); -+ continue; -+ } -+ -+ /* -+ * Check the naming of the file. Only process files -+ * that end with CONF_FILE_EXT -+ */ -+ if (fname_len <= CONF_FILE_EXT_LEN) { -+ xlog(D_GENERAL, "conf_init_dir: %s: name too short", -+ d->d_name); -+ continue; -+ } -+ cname = (d->d_name + (fname_len - CONF_FILE_EXT_LEN)); -+ if (strcmp(cname, CONF_FILE_EXT) != 0) { -+ xlog(D_GENERAL, "conf_init_dir: %s: invalid file extension", -+ d->d_name); -+ continue; -+ } -+ -+ rv = snprintf(fname, PATH_MAX, "%s/%s", dname, d->d_name); -+ if (rv < path_len) { -+ xlog(L_WARNING, "conf_init_dir: file name: %s/%s too short", -+ d->d_name, dname); -+ continue; -+ } -+ -+ if (conf_load_files(trans, fname)) -+ continue; -+ nfiles++; -+ } -+ -+ if (nfiles) { -+ /* Apply the configuration values */ -+ conf_end(trans, 1); -+ } -+ for (i = 0; i < n; i++) -+ free(namelist[i]); -+ free(namelist); -+ free(dname); -+ -+ return; -+} -+ - int - conf_init_file(const char *conf_file) - { - unsigned int i; -+ int ret; - - for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) - LIST_INIT (&conf_bindings[i]); - - TAILQ_INIT (&conf_trans_queue); - -- if (conf_file == NULL) conf_file=NFS_CONFFILE; -- return conf_load_file(conf_file); -+ if (conf_file == NULL) -+ conf_file=NFS_CONFFILE; -+ -+ /* -+ * First parse the give config file -+ * then parse the config.conf.d directory -+ * (if it exists) -+ * -+ */ -+ ret = conf_load_file(conf_file); -+ -+ /* -+ * When the same variable is set in both files -+ * the conf.d file will override the config file. -+ * This allows automated admin systems to -+ * have the final say. -+ */ -+ conf_init_dir(conf_file); -+ -+ return ret; - } - - /* -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 06c1adb..b432f91 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -21,13 +21,13 @@ After=rpc-gssd.service gssproxy.service rpc-svcgssd.service - [Service] - Type=oneshot - RemainAfterExit=yes --ExecStartPre=/usr/sbin/exportfs -r -+ExecStartPre=-/usr/sbin/exportfs -r - ExecStart=/usr/sbin/rpc.nfsd - ExecStop=/usr/sbin/rpc.nfsd 0 - ExecStopPost=/usr/sbin/exportfs -au - ExecStopPost=/usr/sbin/exportfs -f - --ExecReload=/usr/sbin/exportfs -r -+ExecReload=-/usr/sbin/exportfs -r - - [Install] - WantedBy=multi-user.target -diff --git a/systemd/nfs-v4client.target b/systemd/nfs-v4client.target -new file mode 100644 -index 0000000..3d1064e ---- /dev/null -+++ b/systemd/nfs-v4client.target -@@ -0,0 +1,12 @@ -+[Unit] -+Description=NFS client services -+Before=remote-fs-pre.target -+Wants=remote-fs-pre.target -+ -+# GSS services dependencies and ordering -+Wants=auth-rpcgss-module.service -+After=rpc-gssd.service rpc-svcgssd.service gssproxy.service -+ -+[Install] -+WantedBy=multi-user.target -+WantedBy=remote-fs.target -diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man -index 3f1c726..16e0ec4 100644 ---- a/systemd/nfs.conf.man -+++ b/systemd/nfs.conf.man -@@ -265,7 +265,15 @@ Only - is recognized. - - .SH FILES -+.TP 10n - .I /etc/nfs.conf -+Default NFS client configuration file -+.TP 10n -+.I /etc/nfs.conf.d -+When this directory exists and files ending -+with ".conf" exist, those files will be -+used to set configuration variables. These -+files will override variables set in /etc/nfs.conf - .SH SEE ALSO - .BR nfsdcltrack (8), - .BR rpc.nfsd (8), -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 25e92a1..23876fc 100755 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -378,7 +378,10 @@ class DeviceData: - print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) - elif vers == '4': - for op in Nfsv4ops: -- print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ try: -+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ except KeyError: -+ continue - else: - print('\tnot implemented for version %d' % vers) - print() -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 9d5e575..9fcae0b 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -176,10 +176,10 @@ main(int argc, char **argv) - xlog(L_ERROR, "-r and -u are incompatible"); - return 1; - } --printf("point 1\n"); -+ - if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) - return 1; --printf("point 2\n"); -+ - if (optind == argc && ! f_all) { - if (force_flush) { - cache_flush(1); -@@ -193,7 +193,6 @@ printf("point 2\n"); - return 0; - } - } --printf("point 3\n"); - - /* - * Serialize things as best we can -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index 1d17184..54b3f87 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -169,13 +169,6 @@ default. In all releases after 1.0.0, - is the default, and - .I async - must be explicitly requested if needed. --To help make system administrators aware of this change, --.B exportfs --will issue a warning if neither --.I sync --nor --.I async --is specified. - .TP - .IR no_wdelay - This option has no effect if -diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c -index 93fe500..e865998 100644 ---- a/utils/mount/configfile.c -+++ b/utils/mount/configfile.c -@@ -1,5 +1,5 @@ - /* -- * configfile.c -- mount configuration file manipulation -+ * configfile.c -- mount configuration file manipulation - * Copyright (C) 2008 Red Hat, Inc - * - * - Routines use to create mount options from the mount -@@ -34,10 +34,7 @@ - #include "parse_opt.h" - #include "network.h" - #include "conffile.h" -- --char *mountopts_convert(char *value); --char *is_alias(char *opt); --char *conf_get_mntopts(char *spec, char *mount_point, char *mount_opts); -+#include "mount_config.h" - - #define KBYTES(x) ((x) * (1024)) - #define MEGABYTES(x) ((x) * (1048576)) -@@ -70,17 +67,31 @@ struct mnt_alias { - {"background", "bg", MNT_NOARG}, - {"foreground", "fg", MNT_NOARG}, - {"sloppy", "sloppy", MNT_NOARG}, -- {"nfsvers", "vers", MNT_UNSET}, - }; - int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); - -+static const char *version_keys[] = { -+ "v2", "v3", "v4", "vers", "nfsvers", "minorversion", NULL -+}; -+ - static int strict; - -+static int is_version(const char *field) -+{ -+ int i; -+ for (i = 0; version_keys[i] ; i++) -+ if (strcmp(version_keys[i], field) == 0) -+ return 1; -+ if (strncmp(field, "v4.", 3) == 0) -+ return 1; -+ return 0; -+} -+ - /* -- * See if the option is an alias, if so return the -+ * See if the option is an alias, if so return the - * real mount option along with the argument type. - */ --inline static -+inline static - char *mountopts_alias(char *opt, int *argtype) - { - int i; -@@ -99,10 +110,10 @@ char *mountopts_alias(char *opt, int *argtype) - } - /* - * Convert numeric strings that end with 'k', 'm' or 'g' -- * into numeric strings with the real value. -+ * into numeric strings with the real value. - * Meaning '8k' becomes '8094'. - */ --char *mountopts_convert(char *value) -+static char *mountopts_convert(char *value) - { - unsigned long long factor, num; - static char buf[64]; -@@ -136,110 +147,16 @@ char *mountopts_convert(char *value) - return buf; - } - --struct entry { -- SLIST_ENTRY(entry) entries; -- char *opt; --}; --static SLIST_HEAD(shead, entry) head = SLIST_HEAD_INITIALIZER(head); --static int list_size; -- --/* -- * Add option to the link list -- */ --inline static void --add_entry(char *opt) --{ -- struct entry *entry; -- -- entry = calloc(1, sizeof(struct entry)); -- if (entry == NULL) { -- xlog_warn("Unable calloc memory for mount configs"); -- return; -- } -- entry->opt = strdup(opt); -- if (entry->opt == NULL) { -- xlog_warn("Unable calloc memory for mount opts"); -- free(entry); -- return; -- } -- SLIST_INSERT_HEAD(&head, entry, entries); --} --/* -- * Check the alias list to see if the given -- * opt is a alias -- */ --char *is_alias(char *opt) --{ -- int i; -- -- for (i=0; i < mnt_alias_sz; i++) { -- if (strcasecmp(opt, mnt_alias_tab[i].alias) == 0) -- return mnt_alias_tab[i].opt; -- } -- return NULL; --} --/* -- * See if the given entry exists if the link list, -- * if so return that entry -- */ --inline static --char *lookup_entry(char *opt) --{ -- struct entry *entry; -- char *alias = is_alias(opt); -- char *ptr; -- -- SLIST_FOREACH(entry, &head, entries) { -- /* -- * Only check the left side or options that use '=' -- */ -- if ((ptr = strchr(entry->opt, '=')) != 0) { -- int len = (int) (ptr - entry->opt); -- -- if (strncasecmp(entry->opt, opt, len) == 0) -- return opt; -- } -- if (strcasecmp(entry->opt, opt) == 0) -- return opt; -- if (alias && strcasecmp(entry->opt, alias) == 0) -- return opt; -- if (alias && strcasecmp(alias, "fg") == 0) { -- if (strcasecmp(entry->opt, "bg") == 0) -- return opt; -- } -- if (alias && strcasecmp(alias, "bg") == 0) { -- if (strcasecmp(entry->opt, "fg") == 0) -- return opt; -- } -- } -- return NULL; --} --/* -- * Free all entries on the link list -- */ --inline static --void free_all(void) --{ -- struct entry *entry; -- -- while (!SLIST_EMPTY(&head)) { -- entry = SLIST_FIRST(&head); -- SLIST_REMOVE_HEAD(&head, entries); -- free(entry->opt); -- free(entry); -- } --} -- - struct nfs_version config_default_vers; - unsigned long config_default_proto; - extern sa_family_t config_default_family; - - /* - * Check to see if a default value is being set. -- * If so, set the appropriate global value which will -+ * If so, set the appropriate global value which will - * be used as the initial value in the server negation. - */ --static int -+static int - default_value(char *mopt) - { - struct mount_options *options = NULL; -@@ -253,11 +170,11 @@ default_value(char *mopt) - if (strncasecmp(field, "proto", strlen("proto")) == 0) { - if ((options = po_split(field)) != NULL) { - if (!nfs_nfs_protocol(options, &config_default_proto)) { -- xlog_warn("Unable to set default protocol : %s", -+ xlog_warn("Unable to set default protocol : %s", - strerror(errno)); - } - if (!nfs_nfs_proto_family(options, &config_default_family)) { -- xlog_warn("Unable to set default family : %s", -+ xlog_warn("Unable to set default family : %s", - strerror(errno)); - } - } else { -@@ -266,14 +183,13 @@ default_value(char *mopt) - } else if (strncasecmp(field, "vers", strlen("vers")) == 0) { - if ((options = po_split(field)) != NULL) { - if (!nfs_nfs_version("nfs", options, &config_default_vers)) { -- xlog_warn("Unable to set default version: %s", -+ xlog_warn("Unable to set default version: %s", - strerror(errno)); -- - } - } else { - xlog_warn("Unable to alloc memory for default version"); - } -- } else -+ } else - xlog_warn("Invalid default setting: '%s'", mopt); - - if (options) -@@ -282,32 +198,60 @@ default_value(char *mopt) - return 1; - } - /* -- * Parse the given section of the configuration -+ * Parse the given section of the configuration - * file to if there are any mount options set. - * If so, added them to link list. - */ --static void --conf_parse_mntopts(char *section, char *arg, char *opts) -+static void -+conf_parse_mntopts(char *section, char *arg, struct mount_options *options) - { - struct conf_list *list; - struct conf_list_node *node; - char buf[BUFSIZ], *value, *field; - char *nvalue, *ptr; - int argtype; -+ int have_version = 0; -+ -+ if (po_rightmost(options, version_keys) >= 0 || -+ po_contains_prefix(options, "v4.", NULL, 0) == PO_FOUND) -+ have_version = 1; - - list = conf_get_tag_list(section, arg); - TAILQ_FOREACH(node, &list->fields, link) { -- /* check first if this is an alias for another option */ -- field = mountopts_alias(node->field, &argtype); - /* -- * Do not overwrite options if already exists -+ * Do not overwrite options if already exists - */ -- snprintf(buf, BUFSIZ, "%s=", field); -- if (opts && strcasestr(opts, buf) != NULL) -+ field = mountopts_alias(node->field, &argtype); -+ if (po_contains(options, field) == PO_FOUND) -+ continue; -+ /* Some options can be inverted by a "no" prefix. -+ * Check for these. -+ * "no" prefixes are unlikely in the config file as -+ * "option=false" is preferred, but still possible. -+ */ -+ if (strncmp(field, "no", 2) == 0 && -+ po_contains(options, field+2) == PO_FOUND) - continue; -+ if (strlen(field) < BUFSIZ-3) { -+ strcat(strcpy(buf, "no"), field); -+ if (po_contains(options, buf) == PO_FOUND) -+ continue; -+ } - -- if (lookup_entry(field) != NULL) -+ /* If fg or bg already present, ignore bg or fg */ -+ if (strcmp(field, "fg") == 0 && -+ po_contains(options, "bg") == PO_FOUND) - continue; -+ if (strcmp(field, "bg") == 0 && -+ po_contains(options, "fg") == PO_FOUND) -+ continue; -+ -+ if (is_version(field)) { -+ if (have_version) -+ continue; -+ have_version = 1; -+ } -+ - buf[0] = '\0'; - value = conf_get_section(section, arg, node->field); - if (value == NULL) -@@ -333,99 +277,68 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - } - if (buf[0] == '\0') - continue; -- /* -- * Keep a running tally of the list size adding -- * one for the ',' that will be appened later -- */ -- list_size += strlen(buf) + 1; -- add_entry(buf); -+ if (default_value(buf)) -+ continue; -+ -+ po_append(options, buf); - } - conf_free_list(list); - } - - /* -- * Concatenate options from the configuration file with the -+ * Concatenate options from the configuration file with the - * given options by building a link list of options from the -- * different sections in the conf file. Options that exists -- * in the either the given options or link list are not -+ * different sections in the conf file. Options that exists -+ * in the either the given options or link list are not - * overwritten so it matter which when each section is -- * parsed. -+ * parsed. - */ --char *conf_get_mntopts(char *spec, char *mount_point, -- char *mount_opts) -+char *conf_get_mntopts(char *spec, char *mount_point, -+ char *mount_opts) - { -- struct entry *entry; -- char *ptr, *server, *config_opts; -- int optlen = 0; -+ struct mount_options *options; -+ char *ptr, *server; - - strict = 0; -- SLIST_INIT(&head); -- list_size = 0; -+ options = po_split(mount_opts); -+ if (!options) { -+ xlog_warn("conf_get_mountops: Unable calloc memory for options"); -+ return mount_opts; -+ } - /* -- * First see if there are any mount options relative -+ * First see if there are any mount options relative - * to the mount point. - */ -- conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, mount_opts); -+ conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, options); - -- /* -+ /* - * Next, see if there are any mount options relative - * to the server - */ - server = strdup(spec); - if (server == NULL) { -- xlog_warn("conf_get_mountops: Unable calloc memory for server"); -- free_all(); -+ xlog_warn("conf_get_mountops: Unable calloc memory for server"); -+ po_destroy(options); - return mount_opts; - } - if ((ptr = strchr(server, ':')) != NULL) - *ptr='\0'; -- conf_parse_mntopts(NFSMOUNT_SERVER, server, mount_opts); -+ conf_parse_mntopts(NFSMOUNT_SERVER, server, options); - free(server); - - /* -- * Finally process all the global mount options. -- */ -- conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts); -- -- /* -- * If no mount options were found in the configuration file -- * just return what was passed in . -+ * Finally process all the global mount options. - */ -- if (SLIST_EMPTY(&head)) -- return mount_opts; -+ conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, options); - - /* -- * Found options in the configuration file. So -- * concatenate the configuration options with the -- * options that were passed in -+ * Strip out defaults, which have already been handled, -+ * then join the rest and return. - */ -- if (mount_opts) -- optlen = strlen(mount_opts); -- -- /* list_size + optlen + ',' + '\0' */ -- config_opts = calloc(1, (list_size+optlen+2)); -- if (config_opts == NULL) { -- xlog_warn("conf_get_mountops: Unable calloc memory for config_opts"); -- free_all(); -- return mount_opts; -- } -- -- if (mount_opts) { -- strcpy(config_opts, mount_opts); -- strcat(config_opts, ","); -- } -- SLIST_FOREACH(entry, &head, entries) { -- if (default_value(entry->opt)) -- continue; -- strcat(config_opts, entry->opt); -- strcat(config_opts, ","); -- } -- if ((ptr = strrchr(config_opts, ',')) != NULL) -- *ptr = '\0'; -+ po_remove_all(options, "default"); - -- free_all(); -- if (mount_opts) -- free(mount_opts); -+ po_join(options, &mount_opts); -+ po_destroy(options); - -- return config_opts; -+ return mount_opts; - } -diff --git a/utils/mount/network.c b/utils/mount/network.c -index d9c0b51..e803dbb 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -1269,27 +1269,31 @@ int - nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *version) - { - char *version_key, *version_val = NULL, *cptr; -- int i, found = 0; -+ int i, found = -1; - - version->v_mode = V_DEFAULT; - - for (i = 0; nfs_version_opttbl[i]; i++) { - if (po_contains_prefix(options, nfs_version_opttbl[i], -- &version_key) == PO_FOUND) { -- found++; -- break; -+ &version_key, 0) == PO_FOUND) { -+ if (found >= 0) -+ goto ret_error_multiple; -+ if (po_contains_prefix(options, nfs_version_opttbl[i], -+ NULL, 1) == PO_FOUND) -+ goto ret_error_multiple; -+ found = i; - } - } - -- if (!found && strcmp(type, "nfs4") == 0) -+ if (found < 0 && strcmp(type, "nfs4") == 0) - version_val = type + 3; -- else if (!found) -+ else if (found < 0) - return 1; -- else if (i <= 2 ) { -+ else if (found <= 2 ) { - /* v2, v3, v4 */ - version_val = version_key + 1; - version->v_mode = V_SPECIFIC; -- } else if (i > 2 ) { -+ } else if (found > 2 ) { - /* vers=, nfsvers= */ - version_val = po_get(options, version_key); - } -@@ -1303,7 +1307,7 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v - if (version->major == 4 && *cptr != '.' && - (version_val = po_get(options, "minorversion")) != NULL) { - version->minor = strtol(version_val, &cptr, 10); -- i = -1; -+ found = -1; - if (*cptr) - goto ret_error; - version->v_mode = V_SPECIFIC; -@@ -1319,7 +1323,7 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v - if (version_val != NULL) { - version->minor = strtol(version_val, &cptr, 10); - version->v_mode = V_SPECIFIC; -- } else -+ } else - version->v_mode = V_GENERAL; - } - if (*cptr != '\0') -@@ -1327,17 +1331,21 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v - - return 1; - -+ret_error_multiple: -+ nfs_error(_("%s: multiple version options not permitted"), -+ progname); -+ found = 10; /* avoid other errors */ - ret_error: -- if (i < 0) { -+ if (found < 0) { - nfs_error(_("%s: parsing error on 'minorversion=' option"), - progname); -- } else if (i <= 2 ) { -+ } else if (found <= 2 ) { - nfs_error(_("%s: parsing error on 'v' option"), - progname); -- } else if (i == 3 ) { -+ } else if (found == 3 ) { - nfs_error(_("%s: parsing error on 'vers=' option"), - progname); -- } else if (i == 4) { -+ } else if (found == 4) { - nfs_error(_("%s: parsing error on 'nfsvers=' option"), - progname); - } -diff --git a/utils/mount/nfsmount.conf.man b/utils/mount/nfsmount.conf.man -index 3aa3456..73c3e11 100644 ---- a/utils/mount/nfsmount.conf.man -+++ b/utils/mount/nfsmount.conf.man -@@ -1,53 +1,84 @@ --.\"@(#)nfsmount.conf.5" --.TH NFSMOUNT.CONF 5 "9 October 2012" -+."@(#)nfsmount.conf.5" -+.TH NFSMOUNT.CONF 5 "16 December 2020" - .SH NAME - nfsmount.conf - Configuration file for NFS mounts - .SH SYNOPSIS - Configuration file for NFS mounts that allows options - to be set globally, per server or per mount point. - .SH DESCRIPTION --The configuration file is made up of multiple sections --followed by variables associated with that section. --A section is defined by a string enclosed by -+The configuration file is made up of multiple section headers -+followed by variable assignments associated with that section. -+A section header is defined by a string enclosed by - .BR [ --and -+and - .BR ] --branches. --Variables are assignment statements that assign values --to particular variables using the --.BR = --operator, as in -+brackets. -+Variable assignments are assignment statements that assign values -+to particular variables using the -+.BR = -+operator, as in - .BR Proto=Tcp . --The variables that can be assigned are exactly the set of NFS specific -+The variables that can be assigned are the set of NFS specific - mount options listed in --.BR nfs (5). -+.BR nfs (5) -+together with the filesystem-independant mount options listed in -+.BR mount (8) -+and three additions: -+.B Sloppy=True -+has the same effect as the -+.B -s -+option to -+.IR mount , -+and -+.B Foreground=True -+and -+.B Background=True -+have the same effect as -+.B bg -+and -+.BR fg . -+.PP -+Options in the config file may be given in upper, lower, or mixed case -+and will be shifted to lower case before being passed to the filesystem. -+.PP -+Boolean mount options which do not need an equals sign must be given as -+.RI \[dq] option =True". -+Instead of preceeding such an option with -+.RB \[dq] no \[dq] -+its negation must be given as -+.RI \[dq] option =False". - .PP - Sections are broken up into three basic categories: - Global options, Server options and Mount Point options. - .HP - .B [ NFSMount_Global_Options ] - - This statically named section --defines all of the global mount options that can be -+defines all of the global mount options that can be - applied to every NFS mount. - .HP --.B [ Server \(lqServer_Name\(rq ] --- This section defines all the mount options that should --be used on mounts to a particular NFS server. The --.I \(lqServer_Name\(rq --strings needs to be surrounded by '\(lq' and --be an exact match of the server name used in the -+.B [ Server \[dq]Server_Name\[dq] ] -+- This section defines all the mount options that should -+be used on mounts to a particular NFS server. The -+.I \[dq]Server_Name\[dq] -+strings needs to be surrounded by '\[dq]' and be an exact match -+(ignoring case) of the server name used in the - .B mount --command. -+command. - .HP --.B [ MountPoint \(lqMount_Point\(rq ] --- This section defines all the mount options that -+.B [ MountPoint \[dq]Mount_Point\[dq] ] -+- This section defines all the mount options that - should be used on a particular mount point. --The --.I \(lqMount_Point\(rq --string needs to be surrounded by '\(lq' and be an --exact match of the mount point used in the --.BR mount --command. -+The -+.I \[dq]Mount_Point\[dq] -+string needs to be surrounded by '\[dq]' and be an -+exact match of the mount point used in the -+.BR mount -+command. Though path names are usually case-sensitive, the Mount_Point -+name is matched insensitive to case. -+.PP -+The sections are processed in the reverse of the order listed above, and -+any options already seen, either in a previous section or on the -+command line, will be ignored when seen again. - .SH EXAMPLES - .PP - These are some example lines of how sections and variables -@@ -57,37 +88,43 @@ are defined in the configuration file. - .br - Proto=Tcp - .RS --.HP -+.PP - The TCP/IPv4 protocol will be used on every NFS mount. --.HP - .RE --[ Server \(lqnfsserver.foo.com\(rq ] -+.PP -+[ Server \[dq]nfsserver.foo.com\[dq] ] - .br - rsize=32k - .br - wsize=32k - .br - proto=udp6 --.HP - .RS -+.PP - A 32k (32768 bytes) block size will be used as the read and write - size on all mounts to the 'nfsserver.foo.com' server. UDP/IPv6 - is the protocol to be used. --.HP - .RE --.BR --[ MountPoint \(lq/export/home\(rq ] -+.PP -+[ MountPoint \[dq]/export/home\[dq] ] - .br - Background=True - .RS --.HP -+.PP - All mounts to the '/export/home' export will be performed in - the background (i.e. done asynchronously). --.HP -+.RE - .SH FILES - .TP 10n - .I /etc/nfsmount.conf - Default NFS mount configuration file -+.TP 10n -+.I /etc/nfsmount.conf.d -+When this directory exists and files ending -+with ".conf" exist, those files will be -+used to set configuration variables. These -+files will override variables set -+in /etc/nfsmount.conf - .PD - .SH SEE ALSO - .BR nfs (5), -diff --git a/utils/mount/parse_opt.c b/utils/mount/parse_opt.c -index 7ba61c4..b6065ca 100644 ---- a/utils/mount/parse_opt.c -+++ b/utils/mount/parse_opt.c -@@ -414,19 +414,25 @@ po_found_t po_contains(struct mount_options *options, char *keyword) - * @options: pointer to mount options - * @prefix: pointer to prefix to match against a keyword - * @keyword: pointer to a C string containing the option keyword if found -+ * @n: number of instances to skip, so '0' returns the first. - * - * On success, *keyword contains the pointer of the matching option's keyword. - */ - po_found_t po_contains_prefix(struct mount_options *options, -- const char *prefix, char **keyword) -+ const char *prefix, char **keyword, int n) - { - struct mount_option *option; - - if (options && prefix) { - for (option = options->head; option; option = option->next) - if (strncmp(option->keyword, prefix, strlen(prefix)) == 0) { -- *keyword = option->keyword; -- return PO_FOUND; -+ if (n > 0) { -+ n -= 1; -+ } else { -+ if (keyword) -+ *keyword = option->keyword; -+ return PO_FOUND; -+ } - } - } - -diff --git a/utils/mount/parse_opt.h b/utils/mount/parse_opt.h -index 0745e0f..0a15376 100644 ---- a/utils/mount/parse_opt.h -+++ b/utils/mount/parse_opt.h -@@ -46,7 +46,8 @@ po_return_t po_join(struct mount_options *, char **); - po_return_t po_append(struct mount_options *, char *); - po_found_t po_contains(struct mount_options *, char *); - po_found_t po_contains_prefix(struct mount_options *options, -- const char *prefix, char **keyword); -+ const char *prefix, char **keyword, -+ int n); - char * po_get(struct mount_options *, char *); - po_found_t po_get_numeric(struct mount_options *, - char *, long *); -diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c -index dd9828e..6f640aa 100644 ---- a/utils/mountd/v4root.c -+++ b/utils/mountd/v4root.c -@@ -34,9 +34,9 @@ static nfs_export pseudo_root = { - .m_export = { - .e_hostname = "*", - .e_path = "/", -- .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH -+ .e_flags = NFSEXP_READONLY - | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID -- | NFSEXP_V4ROOT, -+ | NFSEXP_V4ROOT | NFSEXP_INSECURE_PORT, - .e_anonuid = 65534, - .e_anongid = 65534, - .e_squids = NULL, -@@ -55,15 +55,11 @@ static nfs_export pseudo_root = { - }; - - static void --set_pseudofs_security(struct exportent *pseudo, int flags) -+set_pseudofs_security(struct exportent *pseudo) - { - struct flav_info *flav; - int i; - -- if (flags & NFSEXP_INSECURE_PORT) -- pseudo->e_flags |= NFSEXP_INSECURE_PORT; -- if ((flags & NFSEXP_ROOTSQUASH) == 0) -- pseudo->e_flags &= ~NFSEXP_ROOTSQUASH; - for (flav = flav_map; flav < flav_map + flav_map_size; flav++) { - struct sec_entry *new; - -@@ -73,8 +69,7 @@ set_pseudofs_security(struct exportent *pseudo, int flags) - i = secinfo_addflavor(flav, pseudo); - new = &pseudo->e_secinfo[i]; - -- if (flags & NFSEXP_INSECURE_PORT) -- new->flags |= NFSEXP_INSECURE_PORT; -+ new->flags |= NFSEXP_INSECURE_PORT; - } - } - -@@ -93,7 +88,7 @@ v4root_create(char *path, nfs_export *export) - strncpy(eep.e_path, path, sizeof(eep.e_path)-1); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; -- set_pseudofs_security(&eep, curexp->e_flags); -+ set_pseudofs_security(&eep); - exp = export_create(&eep, 0); - if (exp == NULL) - return NULL; -@@ -141,7 +136,7 @@ pseudofs_update(char *hostname, char *path, nfs_export *source) - return 0; - } - /* Update an existing V4ROOT export: */ -- set_pseudofs_security(&exp->m_export, source->m_export.e_flags); -+ set_pseudofs_security(&exp->m_export); - return 0; - } - -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index a412a02..c9f0385 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -162,7 +162,7 @@ main(int argc, char **argv) - } - } - -- while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTituUrG:L:", longopts, NULL)) != EOF) { -+ while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTuUrG:L:", longopts, NULL)) != EOF) { - switch(c) { - case 'd': - xlog_config(D_ALL, 1); diff --git a/nfs-utils-2.5.3-rdma-on.patch b/nfs-utils-2.5.3-rdma-on.patch deleted file mode 100644 index 7f8268a..0000000 --- a/nfs-utils-2.5.3-rdma-on.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -up nfs-utils-2.5.3/nfs.conf.orig nfs-utils-2.5.3/nfs.conf ---- nfs-utils-2.5.3/nfs.conf.orig 2021-03-16 13:38:43.922161313 -0400 -+++ nfs-utils-2.5.3/nfs.conf 2021-03-16 13:39:24.560299448 -0400 -@@ -72,9 +72,9 @@ use-gss-proxy=1 - # vers4.0=y - # vers4.1=y - # vers4.2=y --# rdma=n --# rdma-port=20049 --# -+rdma=y -+rdma-port=20049 -+ - [statd] - # debug=0 - # port=0 diff --git a/nfs-utils-2.5.4-rc1.patch b/nfs-utils-2.5.4-rc1.patch deleted file mode 100644 index 5d190da..0000000 --- a/nfs-utils-2.5.4-rc1.patch +++ /dev/null @@ -1,1244 +0,0 @@ -diff --git a/nfs.conf b/nfs.conf -index bebb2e3d..9042d27d 100644 ---- a/nfs.conf -+++ b/nfs.conf -@@ -24,6 +24,7 @@ - # keytab-file=/etc/krb5.keytab - # cred-cache-directory= - # preferred-realm= -+# set-home=1 - # - [lockd] - # port=0 -@@ -31,8 +32,11 @@ - # - [exportd] - # debug="all|auth|call|general|parse" -+# manage-gids=n - # state-directory-path=/var/lib/nfs - # threads=1 -+# cache-use-ipaddr=n -+# ttl=1800 - [mountd] - # debug="all|auth|call|general|parse" - # manage-gids=n -@@ -42,6 +46,8 @@ - # reverse-lookup=n - # state-directory-path=/var/lib/nfs - # ha-callout= -+# cache-use-ipaddr=n -+# ttl=1800 - # - [nfsdcld] - # debug=0 -diff --git a/support/export/Makefile.am b/support/export/Makefile.am -index a9e710c0..eec737f6 100644 ---- a/support/export/Makefile.am -+++ b/support/export/Makefile.am -@@ -12,7 +12,8 @@ EXTRA_DIST = mount.x - noinst_LIBRARIES = libexport.a - libexport_a_SOURCES = client.c export.c hostname.c \ - xtab.c mount_clnt.c mount_xdr.c \ -- cache.c auth.c v4root.c fsloc.c -+ cache.c auth.c v4root.c fsloc.c \ -+ v4clients.c - BUILT_SOURCES = $(GENFILES) - - noinst_HEADERS = mount.h -diff --git a/support/export/auth.c b/support/export/auth.c -index 0bfa77d1..cea37630 100644 ---- a/support/export/auth.c -+++ b/support/export/auth.c -@@ -66,6 +66,10 @@ check_useipaddr(void) - int old_use_ipaddr = use_ipaddr; - unsigned int len = 0; - -+ if (use_ipaddr > 1) -+ /* fixed - don't check */ -+ return; -+ - /* add length of m_hostname + 1 for the comma */ - for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next) - len += (strlen(clp->m_hostname) + 1); -diff --git a/support/export/cache.c b/support/export/cache.c -index f1569afb..3e4f53c0 100644 ---- a/support/export/cache.c -+++ b/support/export/cache.c -@@ -42,13 +42,6 @@ - #include "blkid/blkid.h" - #endif - --/* -- * Invoked by RPC service loop -- */ --void cache_set_fds(fd_set *fdset); --int cache_process_req(fd_set *readfds); --void cache_process_loop(void); -- - enum nfsd_fsid { - FSID_DEV = 0, - FSID_NUM, -@@ -96,7 +89,6 @@ static bool path_lookup_error(int err) - * Record is terminated with newline. - * - */ --static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path); - - #define INITIAL_MANAGED_GROUPS 100 - -@@ -114,6 +106,7 @@ static void auth_unix_ip(int f) - char class[20]; - char ipaddr[INET6_ADDRSTRLEN + 1]; - char *client = NULL; -+ struct addrinfo *ai = NULL; - struct addrinfo *tmp = NULL; - char buf[RPC_CHAN_BUF_SIZE], *bp; - int blen; -@@ -139,21 +132,26 @@ static void auth_unix_ip(int f) - - auth_reload(); - -- /* addr is a valid, interesting address, find the domain name... */ -- if (!use_ipaddr) { -- struct addrinfo *ai = NULL; -- -- ai = client_resolve(tmp->ai_addr); -- if (ai) { -- client = client_compose(ai); -- nfs_freeaddrinfo(ai); -- } -+ /* addr is a valid address, find the domain name... */ -+ ai = client_resolve(tmp->ai_addr); -+ if (ai) { -+ client = client_compose(ai); -+ nfs_freeaddrinfo(ai); - } -+ if (!client) -+ xlog(D_AUTH, "failed authentication for IP %s", ipaddr); -+ else if (!use_ipaddr) -+ xlog(D_AUTH, "successful authentication for IP %s as %s", -+ ipaddr, *client ? client : "DEFAULT"); -+ else -+ xlog(D_AUTH, "successful authentication for IP %s", -+ ipaddr); -+ - bp = buf; blen = sizeof(buf); - qword_add(&bp, &blen, "nfsd"); - qword_add(&bp, &blen, ipaddr); -- qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); -- if (use_ipaddr) { -+ qword_adduint(&bp, &blen, time(0) + default_ttl); -+ if (use_ipaddr && client) { - memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1); - ipaddr[0] = '$'; - qword_add(&bp, &blen, ipaddr); -@@ -225,7 +223,7 @@ static void auth_unix_gid(int f) - - bp = buf; blen = sizeof(buf); - qword_adduint(&bp, &blen, uid); -- qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); -+ qword_adduint(&bp, &blen, time(0) + default_ttl); - if (rv >= 0) { - qword_adduint(&bp, &blen, ngroups); - for (i=0; ie_mountpoint[0]? - found->e_mountpoint: - found->e_path)) { -- /* Cannot export this yet -+ /* Cannot export this yet - * should log a warning, but need to rate limit - xlog(L_WARNING, "%s not exported as %d not a mountpoint", - found->e_path, found->e_mountpoint); - */ - /* FIXME we need to make sure we re-visit this later */ - goto out; -- } else if (cache_export_ent(buf, sizeof(buf), dom, found, found_path) < 0) { -- if (!path_lookup_error(errno)) -- goto out; -- /* The kernel is saying the path is unexportable */ -- found = NULL; - } - - bp = buf; blen = sizeof(buf); -@@ -905,6 +898,8 @@ static void nfsd_fh(int f) - qword_addeol(&bp, &blen); - if (blen <= 0 || cache_write(f, buf, bp - buf) != bp - buf) - xlog(L_ERROR, "nfsd_fh: error writing reply"); -+ if (!found) -+ xlog(D_AUTH, "denied access to %s", *dom == '$' ? dom+1 : dom); - out: - if (found_path) - free(found_path); -@@ -966,7 +961,7 @@ static int dump_to_cache(int f, char *buf, int blen, char *domain, - ssize_t err; - - if (ttl <= 1) -- ttl = DEFAULT_TTL; -+ ttl = default_ttl; - - qword_add(&bp, &blen, domain); - qword_add(&bp, &blen, path); -@@ -996,8 +991,13 @@ static int dump_to_cache(int f, char *buf, int blen, char *domain, - qword_add(&bp, &blen, "uuid"); - qword_addhex(&bp, &blen, u, 16); - } -- } else -+ xlog(D_AUTH, "granted access to %s for %s", -+ path, *domain == '$' ? domain+1 : domain); -+ } else { - qword_adduint(&bp, &blen, now + ttl); -+ xlog(D_AUTH, "denied access to %s for %s", -+ path, *domain == '$' ? domain+1 : domain); -+ } - qword_addeol(&bp, &blen); - if (blen <= 0) { - errno = ENOBUFS; -@@ -1530,6 +1530,7 @@ void cache_process_loop(void) - for (;;) { - - cache_set_fds(&readfds); -+ v4clients_set_fds(&readfds); - - selret = select(FD_SETSIZE, &readfds, - (void *) 0, (void *) 0, (struct timeval *) 0); -@@ -1545,6 +1546,7 @@ void cache_process_loop(void) - - default: - cache_process_req(&readfds); -+ v4clients_process(&readfds); - } - } - } -diff --git a/support/export/export.h b/support/export/export.h -index 4296db1a..8d5a0d30 100644 ---- a/support/export/export.h -+++ b/support/export/export.h -@@ -3,13 +3,14 @@ - * - * support/export/export.h - * -- * Declarations for export support -+ * Declarations for export support - */ - - #ifndef EXPORT_H - #define EXPORT_H - - #include "nfslib.h" -+#include "exportfs.h" - - unsigned int auth_reload(void); - nfs_export * auth_authenticate(const char *what, -@@ -17,8 +18,14 @@ nfs_export * auth_authenticate(const char *what, - const char *path); - - void cache_open(void); -+void cache_set_fds(fd_set *fdset); -+int cache_process_req(fd_set *readfds); - void cache_process_loop(void); - -+void v4clients_init(void); -+void v4clients_set_fds(fd_set *fdset); -+int v4clients_process(fd_set *fdset); -+ - struct nfs_fh_len * - cache_get_filehandle(nfs_export *exp, int len, char *p); - int cache_export(nfs_export *exp, char *path); -diff --git a/support/export/v4clients.c b/support/export/v4clients.c -new file mode 100644 -index 00000000..056ddc9b ---- /dev/null -+++ b/support/export/v4clients.c -@@ -0,0 +1,179 @@ -+/* -+ * support/export/v4clients.c -+ * -+ * Montior clients appearing in, and disappearing from, /proc/fs/nfsd/clients -+ * and log relevant information. -+ */ -+ -+#include -+#include -+#include -+#include -+#include "export.h" -+ -+/* search.h declares 'struct entry' and nfs_prot.h -+ * does too. Easiest fix is to trick search.h into -+ * calling its struct "struct Entry". -+ */ -+#define entry Entry -+#include -+#undef entry -+ -+static int clients_fd = -1; -+ -+void v4clients_init(void) -+{ -+ if (clients_fd >= 0) -+ return; -+ clients_fd = inotify_init1(IN_NONBLOCK); -+ if (clients_fd < 0) { -+ xlog_err("Unable to initialise v4clients watcher: %s\n", -+ strerror(errno)); -+ return; -+ } -+ if (inotify_add_watch(clients_fd, "/proc/fs/nfsd/clients", -+ IN_CREATE | IN_DELETE) < 0) { -+ xlog_err("Unable to watch /proc/fs/nfsd/clients: %s\n", -+ strerror(errno)); -+ close(clients_fd); -+ clients_fd = -1; -+ return; -+ } -+} -+ -+void v4clients_set_fds(fd_set *fdset) -+{ -+ if (clients_fd >= 0) -+ FD_SET(clients_fd, fdset); -+} -+ -+static void *tree_root; -+ -+struct ent { -+ unsigned long num; -+ char *clientid; -+ char *addr; -+ int vers; -+}; -+ -+static int ent_cmp(const void *av, const void *bv) -+{ -+ const struct ent *a = av; -+ const struct ent *b = bv; -+ -+ if (a->num < b->num) -+ return -1; -+ if (a->num > b->num) -+ return 1; -+ return 0; -+} -+ -+static void free_ent(struct ent *ent) -+{ -+ free(ent->clientid); -+ free(ent->addr); -+ free(ent); -+} -+ -+static char *dup_line(char *line) -+{ -+ char *ret; -+ char *e = strchr(line, '\n'); -+ if (!e) -+ e = line + strlen(line); -+ ret = malloc(e - line + 1); -+ if (ret) { -+ memcpy(ret, line, e - line); -+ ret[e-line] = 0; -+ } -+ return ret; -+} -+ -+static void add_id(int id) -+{ -+ char buf[2048]; -+ struct ent **ent; -+ struct ent *key; -+ char *path; -+ FILE *f; -+ -+ if (asprintf(&path, "/proc/fs/nfsd/clients/%d/info", id) < 0) -+ return; -+ -+ f = fopen(path, "r"); -+ if (!f) { -+ free(path); -+ return; -+ } -+ key = calloc(1, sizeof(*key)); -+ if (!key) { -+ fclose(f); -+ free(path); -+ return; -+ } -+ key->num = id; -+ while (fgets(buf, sizeof(buf), f)) { -+ if (strncmp(buf, "clientid: ", 10) == 0) -+ key->clientid = dup_line(buf+10); -+ if (strncmp(buf, "address: ", 9) == 0) -+ key->addr = dup_line(buf+9); -+ if (strncmp(buf, "minor version: ", 15) == 0) -+ key->vers = atoi(buf+15); -+ } -+ fclose(f); -+ free(path); -+ -+ xlog(L_NOTICE, "v4.%d client attached: %s from %s", -+ key->vers, key->clientid, key->addr); -+ -+ ent = tsearch(key, &tree_root, ent_cmp); -+ -+ if (!ent || *ent != key) -+ /* Already existed, or insertion failed */ -+ free_ent(key); -+} -+ -+static void del_id(int id) -+{ -+ struct ent key = {.num = id}; -+ struct ent **e, *ent; -+ -+ e = tfind(&key, &tree_root, ent_cmp); -+ if (!e || !*e) -+ return; -+ ent = *e; -+ tdelete(ent, &tree_root, ent_cmp); -+ xlog(L_NOTICE, "v4.%d client detached: %s from %s", -+ ent->vers, ent->clientid, ent->addr); -+ free_ent(ent); -+} -+ -+int v4clients_process(fd_set *fdset) -+{ -+ char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); -+ const struct inotify_event *ev; -+ ssize_t len; -+ char *ptr; -+ -+ if (clients_fd < 0 || -+ !FD_ISSET(clients_fd, fdset)) -+ return 0; -+ -+ while ((len = read(clients_fd, buf, sizeof(buf))) > 0) { -+ for (ptr = buf; ptr < buf + len; -+ ptr += sizeof(struct inotify_event) + ev->len) { -+ int id; -+ ev = (const struct inotify_event *)ptr; -+ -+ id = atoi(ev->name); -+ if (id <= 0) -+ continue; -+ if (ev->mask & IN_CREATE) -+ add_id(id); -+ if (ev->mask & IN_DELETE) -+ del_id(id); -+ } -+ } -+ return 1; -+} -+ -diff --git a/support/export/v4root.c b/support/export/v4root.c -index 6f640aa9..3654bd7c 100644 ---- a/support/export/v4root.c -+++ b/support/export/v4root.c -@@ -45,7 +45,7 @@ static nfs_export pseudo_root = { - .e_nsqgids = 0, - .e_fsid = 0, - .e_mountpoint = NULL, -- .e_ttl = DEFAULT_TTL, -+ .e_ttl = 0, - }, - .m_exported = 0, - .m_xtabent = 1, -@@ -84,6 +84,7 @@ v4root_create(char *path, nfs_export *export) - struct exportent *curexp = &export->m_export; - - dupexportent(&eep, &pseudo_root.m_export); -+ eep.e_ttl = default_ttl; - eep.e_hostname = curexp->e_hostname; - strncpy(eep.e_path, path, sizeof(eep.e_path)-1); - if (strcmp(path, "/") != 0) -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index daa7e2a0..81d13721 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -105,7 +105,8 @@ typedef struct mexport { - } nfs_export; - - #define HASH_TABLE_SIZE 1021 --#define DEFAULT_TTL (30 * 60) -+ -+extern int default_ttl; - - typedef struct _exp_hash_entry { - nfs_export * p_first; -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index 037febd0..2c8f0752 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -47,6 +47,8 @@ struct flav_info flav_map[] = { - - const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]); - -+int default_ttl = 30 * 60; -+ - static char *efname = NULL; - static XFILE *efp = NULL; - static int first; -@@ -100,7 +102,7 @@ static void init_exportent (struct exportent *ee, int fromkernel) - ee->e_nsquids = 0; - ee->e_nsqgids = 0; - ee->e_uuid = NULL; -- ee->e_ttl = DEFAULT_TTL; -+ ee->e_ttl = default_ttl; - } - - struct exportent * -diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man -index d2187f8a..4436a38a 100644 ---- a/systemd/nfs.conf.man -+++ b/systemd/nfs.conf.man -@@ -132,12 +132,22 @@ but on the server, this will resolve to the path - .B exportd - Recognized values: - .BR threads , -+.BR cache-use-upaddr , -+.BR ttl , - .BR state-directory-path - - See - .BR exportd (8) - for details. - -+Note that setting -+.B "\[dq]debug = auth\[dq]" -+for -+.B exportd -+is equivalent to providing the -+.B \-\-log\-auth -+option. -+ - .TP - .B nfsdcltrack - Recognized values: -@@ -188,6 +198,8 @@ Recognized values: - .BR port , - .BR threads , - .BR reverse-lookup , -+.BR cache-use-upaddr , -+.BR ttl , - .BR state-directory-path , - .BR ha-callout . - -@@ -197,6 +209,14 @@ section, are used to configure mountd. See - .BR rpc.mountd (8) - for details. - -+Note that setting -+.B "\[dq]debug = auth\[dq]" -+for -+.B mountd -+is equivalent to providing the -+.B \-\-log\-auth -+option. -+ - The - .B state-directory-path - value in the -@@ -253,7 +273,8 @@ Recognized values: - .BR rpc-timeout , - .BR keytab-file , - .BR cred-cache-directory , --.BR preferred-realm . -+.BR preferred-realm , -+.BR set-home . - - See - .BR rpc.gssd (8) -diff --git a/tools/nfsdclnts/nfsdclnts.py b/tools/nfsdclnts/nfsdclnts.py -index 5e7e03c2..b7280f2c 100755 ---- a/tools/nfsdclnts/nfsdclnts.py -+++ b/tools/nfsdclnts/nfsdclnts.py -@@ -223,6 +223,7 @@ def nfsd4_show(): - - global verbose - verbose = False -+ signal.signal(signal.SIGPIPE, signal.SIG_DFL) - if args.verbose: - verbose = True - -diff --git a/utils/exportd/exportd.c b/utils/exportd/exportd.c -index 7130bcbf..f36f51d2 100644 ---- a/utils/exportd/exportd.c -+++ b/utils/exportd/exportd.c -@@ -42,9 +42,14 @@ static struct option longopts[] = - { "foreground", 0, 0, 'F' }, - { "debug", 1, 0, 'd' }, - { "help", 0, 0, 'h' }, -+ { "manage-gids", 0, 0, 'g' }, - { "num-threads", 1, 0, 't' }, -+ { "log-auth", 0, 0, 'l' }, -+ { "cache-use-ipaddr", 0, 0, 'i' }, -+ { "ttl", 0, 0, 'T' }, - { NULL, 0, 0, 0 } - }; -+static char shortopts[] = "d:fghs:t:liT:"; - - /* - * Signal handlers. -@@ -174,33 +179,43 @@ usage(const char *prog, int n) - { - fprintf(stderr, - "Usage: %s [-f|--foreground] [-h|--help] [-d kind|--debug kind]\n" -+" [-g|--manage-gids] [-l|--log-auth] [-i|--cache-use-ipaddr] [-T|--ttl ttl]\n" - " [-s|--state-directory-path path]\n" - " [-t num|--num-threads=num]\n", prog); - exit(n); - } - --inline static void -+inline static void - read_exportd_conf(char *progname, char **argv) - { - char *s; -+ int ttl; - - conf_init_file(NFS_CONFFILE); - - xlog_set_debug(progname); - -+ manage_gids = conf_get_bool("exportd", "manage-gids", manage_gids); - num_threads = conf_get_num("exportd", "threads", num_threads); -+ if (conf_get_bool("mountd", "cache-use-ipaddr", 0)) -+ use_ipaddr = 2; - - s = conf_get_str("exportd", "state-directory-path"); - if (s && !state_setup_basedir(argv[0], s)) - exit(1); -+ -+ ttl = conf_get_num("mountd", "ttl", default_ttl); -+ if (ttl > 0) -+ default_ttl = ttl; - } - - int - main(int argc, char **argv) - { - char *progname; -- int foreground = 0; -- int c; -+ int foreground = 0; -+ int c; -+ int ttl; - - /* Set the basename */ - if ((progname = strrchr(argv[0], '/')) != NULL) -@@ -214,17 +229,35 @@ main(int argc, char **argv) - /* Read in config setting */ - read_exportd_conf(progname, argv); - -- while ((c = getopt_long(argc, argv, "d:fhs:t:", longopts, NULL)) != EOF) { -+ while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF) { - switch (c) { - case 'd': - xlog_sconfig(optarg, 1); - break; -+ case 'l': -+ xlog_sconfig("auth", 1); -+ break; - case 'f': - foreground++; - break; -+ case 'g': -+ manage_gids = 1; -+ break; - case 'h': - usage(progname, 0); - break; -+ case 'i': -+ use_ipaddr = 2; -+ break; -+ case 'T': -+ ttl = atoi(optarg); -+ if (ttl <= 0) { -+ fprintf(stderr, "%s: bad ttl number of seconds: %s\n", -+ argv[0], optarg); -+ usage(argv[0], 1); -+ } -+ default_ttl = ttl; -+ break; - case 's': - if (!state_setup_basedir(argv[0], optarg)) - exit(1); -@@ -241,8 +274,8 @@ main(int argc, char **argv) - - if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) - return 1; -- -- if (!foreground) -+ -+ if (!foreground) - xlog_stderr(0); - - daemon_init(foreground); -@@ -264,6 +297,7 @@ main(int argc, char **argv) - - /* Open files now to avoid sharing descriptors among forked processes */ - cache_open(); -+ v4clients_init(); - - /* Process incoming upcalls */ - cache_process_loop(); -diff --git a/utils/exportd/exportd.man b/utils/exportd/exportd.man -index 1d65b5e0..b238ff05 100644 ---- a/utils/exportd/exportd.man -+++ b/utils/exportd/exportd.man -@@ -10,35 +10,74 @@ nfsv4.exportd \- NFSv4 Server Mount Daemon - .SH DESCRIPTION - The - .B nfsv4.exportd --is used to manage NFSv4 exports. The NFSv4 server --receives a mount request from a client and pass it up to --.B nfsv4.exportd. --.B nfsv4.exportd --then uses the exports(5) export --table to verify the validity of the mount request. --.PP --An NFS server maintains a table of local physical file systems --that are accessible to NFS clients. --Each file system in this table is referred to as an --.IR "exported file system" , --or --.IR export , --for short. --.PP --Each file system in the export table has an access control list. -+is used to manage NFSv4 exports. -+The NFS server -+.RI ( nfsd ) -+maintains a cache of authentication and authorization information which -+is used to identify the source of each requent, and then what access -+permissions that source has to any local filesystem. When required -+information is not found in the cache, the server sends a request to - .B nfsv4.exportd --uses these access control lists to determine --whether an NFS client is permitted to access a given file system. --For details on how to manage your NFS server's export table, see the --.BR exports (5) --and --.BR exportfs (8) --man pages. -+to fill in the missing information. -+.B nfsv4.exportd -+uses a table of information stored in -+.B /var/lib/nfs/etab -+and maintained by -+.BR exportfs (8), -+possibly based on the contents of -+.BR exports (5), -+to respond to each request. - .SH OPTIONS - .TP - .B \-d kind " or " \-\-debug kind - Turn on debugging. Valid kinds are: all, auth, call, general and parse. - .TP -+.BR \-l " or " \-\-log\-auth -+Enable logging of responses to authentication and access requests from -+nfsd. Each response is then cached by the kernel for 30 minutes (or as set by -+.B \-\-ttl -+below), and will be refreshed after 15 minutes (half the ttl time) if -+the relevant client remains active. -+Note that -+.B -l -+is equivalent to -+.B "-d auth" -+and so can be enabled in -+.B /etc/nfs.conf -+with -+.B "\[dq]debug = auth\[dq]" -+in the -+.B "[exportd]" -+section. -+.TP -+.BR \-i " or " \-\-cache\-use\-ipaddr -+Normally each client IP address is matched against each host identifier -+(name, wildcard, netgroup etc) found in -+.B /etc/exports -+and a combined identity is formed from all matching identifiers. -+Often many clients will map to the same combined identity so performing -+this mapping reduces the number of distinct access details that the -+kernel needs to store. -+Specifying the -+.B \-i -+option suppresses this mapping so that access to each filesystem is -+requested and cached separately for each client IP address. Doing this -+can increase the burden of updating the cache slightly, but can make the -+log messages produced by the -+.B -l -+option easier to read. -+.TP -+.B \-T " or " \-\-ttl -+Provide a time-to-live (TTL) for cached information given to the kernel. -+The kernel will normally request an update if the information is needed -+after half of this time has expired. Increasing the provided number, -+which is in seconds, reduces the rate of cache update requests, and this -+is particularly noticeable when these requests are logged with -+.BR \-l . -+However increasing also means that changes to hostname to address -+mappings can take longer to be noticed. -+The default TTL is 1800 (30 minutes). -+.TP - .B \-F " or " \-\-foreground - Run in foreground (do not daemonize) - .TP -@@ -46,11 +85,27 @@ Run in foreground (do not daemonize) - Display usage message. - .TP - .BR "\-t N" " or " "\-\-num\-threads=N " or " \-\-num\-threads N " --This option specifies the number of worker threads that rpc.mountd -+This option specifies the number of worker threads that -+.B nfsv4.exports - spawns. The default is 1 thread, which is probably enough. More - threads are usually only needed for NFS servers which need to handle - mount storms of hundreds of NFS mounts in a few seconds, or when - your DNS server is slow or unreliable. -+.TP -+.BR \-g " or " \-\-manage-gids -+Accept requests from the kernel to map user id numbers into lists of -+group id numbers for use in access control. An NFS request will -+normally (except when using Kerberos or other cryptographic -+authentication) contain a user-id and a list of group-ids. Due to a -+limitation in the NFS protocol, at most 16 groups ids can be listed. -+If you use the -+.B \-g -+flag, then the list of group ids received from the client will be -+replaced by a list of group ids determined by an appropriate lookup on -+the server. Note that the 'primary' group id is not affected so a -+.B newgroup -+command on the client will still be effective. This function requires -+a Linux Kernel with version at least 2.6.21. - .SH CONFIGURATION FILE - Many of the options that can be set on the command line can also be - controlled through values set in the -@@ -63,6 +118,9 @@ configuration file. - Values recognized in the - .B [exportd] - section include -+.B cache\-use\-ipaddr , -+.BR ttl , -+.BR manage-gids ", and" - .B debug - which each have the same effect as the option with the same name. - .SH FILES -@@ -78,4 +136,6 @@ listing exports, export options, and access control lists - .BR nfs.conf (5), - .BR firwall-cmd (1), - .sp --RFC 3530 - "Network File System (NFS) version 4 Protocol" -+RFC 7530 - "Network File System (NFS) Version 4 Protocol" -+.br -+RFC 8881 - "Network File System (NFS) Version 4 Minor Version 1 Protocol" -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 85bc4b07..1541d371 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -87,6 +87,8 @@ unsigned int context_timeout = 0; - unsigned int rpc_timeout = 5; - char *preferred_realm = NULL; - char *ccachedir = NULL; -+/* set $HOME to "/" by default */ -+static bool set_home = true; - /* Avoid DNS reverse lookups on server names */ - static bool avoid_dns = true; - static bool use_gssproxy = false; -@@ -900,7 +902,7 @@ sig_die(int signal) - static void - usage(char *progname) - { -- fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D]\n", -+ fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D] [-H]\n", - progname); - exit(1); - } -@@ -941,6 +943,7 @@ read_gss_conf(void) - preferred_realm = s; - - use_gssproxy = conf_get_bool("gssd", "use-gss-proxy", use_gssproxy); -+ set_home = conf_get_bool("gssd", "set-home", set_home); - } - - int -@@ -961,7 +964,7 @@ main(int argc, char *argv[]) - verbosity = conf_get_num("gssd", "verbosity", verbosity); - rpc_verbosity = conf_get_num("gssd", "rpc-verbosity", rpc_verbosity); - -- while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { -+ while ((opt = getopt(argc, argv, "HDfvrlmnMp:k:d:t:T:R:")) != -1) { - switch (opt) { - case 'f': - fg = 1; -@@ -1009,6 +1012,9 @@ main(int argc, char *argv[]) - case 'D': - avoid_dns = false; - break; -+ case 'H': -+ set_home = false; -+ break; - default: - usage(argv[0]); - break; -@@ -1018,13 +1024,19 @@ main(int argc, char *argv[]) - /* - * Some krb5 routines try to scrape info out of files in the user's - * home directory. This can easily deadlock when that homedir is on a -- * kerberized NFS mount. By setting $HOME unconditionally to "/", we -- * prevent this behavior in routines that use $HOME in preference to -- * the results of getpw*. -+ * kerberized NFS mount. By setting $HOME to "/" by default, we prevent -+ * this behavior in routines that use $HOME in preference to the results -+ * of getpw*. -+ * -+ * Some users do not use Kerberized home dirs and need $HOME to remain -+ * unchanged. Those users can leave $HOME unchanged by setting set_home -+ * to false. - */ -- if (setenv("HOME", "/", 1)) { -- printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); -- exit(1); -+ if (set_home) { -+ if (setenv("HOME", "/", 1)) { -+ printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); -+ exit(1); -+ } - } - - if (use_gssproxy) { -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 26095a89..9ae6def9 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -8,7 +8,7 @@ - rpc.gssd \- RPCSEC_GSS daemon - .SH SYNOPSIS - .B rpc.gssd --.RB [ \-DfMnlvr ] -+.RB [ \-DfMnlvrH ] - .RB [ \-k - .IR keytab ] - .RB [ \-p -@@ -282,6 +282,16 @@ The default timeout is set to 5 seconds. - If you get messages like "WARNING: can't create tcp rpc_clnt to server - %servername% for user with uid %uid%: RPC: Remote system error - - Connection timed out", you should consider an increase of this timeout. -+.TP -+.B -H -+Avoids setting $HOME to "/". This allows rpc.gssd to read per user k5identity -+files versus trying to read /.k5identity for each user. -+ -+If -+.B \-H -+is not set, rpc.gssd will use the first match found in -+/var/kerberos/krb5/user/$EUID/client.keytab and will not use a principal based on -+host and/or service parameters listed in $HOME/.k5identity. - .SH CONFIGURATION FILE - Many of the options that can be set on the command line can also be - controlled through values set in the -@@ -339,6 +349,13 @@ Equivalent to - .B preferred-realm - Equivalent to - .BR -R . -+.TP -+.B set-home -+Setting to -+.B false -+is equivalent to providing the -+.B -H -+flag. - .P - In addtion, the following value is recognized from the - .B [general] -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 612063ba..39e85fd5 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -31,6 +31,7 @@ - #include "pseudoflavors.h" - #include "nfsd_path.h" - #include "nfslib.h" -+#include "export.h" - - extern void my_svc_run(void); - -@@ -74,8 +75,12 @@ static struct option longopts[] = - { "reverse-lookup", 0, 0, 'r' }, - { "manage-gids", 0, 0, 'g' }, - { "no-udp", 0, 0, 'u' }, -+ { "log-auth", 0, 0, 'l'}, -+ { "cache-use-ipaddr", 0, 0, 'i'}, -+ { "ttl", 1, 0, 'T'}, - { NULL, 0, 0, 0 } - }; -+static char shortopts[] = "o:nFd:p:P:hH:N:V:vurs:t:gliT:"; - - #define NFSVERSBIT(vers) (0x1 << (vers - 1)) - #define NFSVERSBIT_ALL (NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4)) -@@ -669,6 +674,7 @@ inline static void - read_mountd_conf(char **argv) - { - char *s; -+ int ttl; - - conf_init_file(NFS_CONFFILE); - -@@ -679,6 +685,8 @@ read_mountd_conf(char **argv) - num_threads = conf_get_num("mountd", "threads", num_threads); - reverse_resolve = conf_get_bool("mountd", "reverse-lookup", reverse_resolve); - ha_callout_prog = conf_get_str("mountd", "ha-callout"); -+ if (conf_get_bool("mountd", "cache-use-ipaddr", 0)) -+ use_ipaddr = 2; - - s = conf_get_str("mountd", "state-directory-path"); - if (s && !state_setup_basedir(argv[0], s)) -@@ -701,6 +709,10 @@ read_mountd_conf(char **argv) - else - NFSCTL_VERUNSET(nfs_version, vers); - } -+ -+ ttl = conf_get_num("mountd", "ttl", default_ttl); -+ if (ttl > 0) -+ default_ttl = ttl; - } - - int -@@ -710,6 +722,7 @@ main(int argc, char **argv) - unsigned int listeners = 0; - int foreground = 0; - int c; -+ int ttl; - struct sigaction sa; - struct rlimit rlim; - -@@ -727,7 +740,7 @@ main(int argc, char **argv) - - /* Parse the command line options and arguments. */ - opterr = 0; -- while ((c = getopt_long(argc, argv, "o:nFd:p:P:hH:N:V:vurs:t:g", longopts, NULL)) != EOF) -+ while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF) - switch (c) { - case 'g': - manage_gids = 1; -@@ -798,6 +811,21 @@ main(int argc, char **argv) - case 'u': - NFSCTL_UDPUNSET(_rpcprotobits); - break; -+ case 'l': -+ xlog_sconfig("auth", 1); -+ break; -+ case 'i': -+ use_ipaddr = 2; -+ break; -+ case 'T': -+ ttl = atoi(optarg); -+ if (ttl <= 0) { -+ fprintf(stderr, "%s: bad ttl number of seconds: %s\n", -+ argv[0], optarg); -+ usage(argv[0], 1); -+ } -+ default_ttl = ttl; -+ break; - case 0: - break; - case '?': -@@ -897,6 +925,7 @@ main(int argc, char **argv) - nfsd_path_init(); - /* Open files now to avoid sharing descriptors among forked processes */ - cache_open(); -+ v4clients_init(); - - xlog(L_NOTICE, "Version " VERSION " starting"); - my_svc_run(); -@@ -913,6 +942,7 @@ usage(const char *prog, int n) - { - fprintf(stderr, - "Usage: %s [-F|--foreground] [-h|--help] [-v|--version] [-d kind|--debug kind]\n" -+" [-l|--log-auth] [-i|--cache-use-ipaddr] [-T|--ttl ttl]\n" - " [-o num|--descriptors num]\n" - " [-p|--port port] [-V version|--nfs-version version]\n" - " [-N version|--no-nfs-version version] [-n|--no-tcp]\n" -diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h -index f058f01d..d3077531 100644 ---- a/utils/mountd/mountd.h -+++ b/utils/mountd/mountd.h -@@ -60,9 +60,4 @@ bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai); - bool namelist_client_matches(nfs_export *exp, char *dom); - bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai); - --static inline bool is_ipaddr_client(char *dom) --{ -- return dom[0] == '$'; --} -- - #endif /* MOUNTD_H */ -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index 9978afcd..1155cf94 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -13,24 +13,24 @@ The - .B rpc.mountd - daemon implements the server side of the NFS MOUNT protocol, - an NFS side protocol used by NFS version 2 [RFC1094] and NFS version 3 [RFC1813]. -+It also responds to requests from the Linux kernel to authenticate -+clients and provides details of access permissions. - .PP --An NFS server maintains a table of local physical file systems --that are accessible to NFS clients. --Each file system in this table is referred to as an --.IR "exported file system" , --or --.IR export , --for short. --.PP --Each file system in the export table has an access control list. --.B rpc.mountd --uses these access control lists to determine --whether an NFS client is permitted to access a given file system. --For details on how to manage your NFS server's export table, see the --.BR exports (5) --and --.BR exportfs (8) --man pages. -+The NFS server -+.RI ( nfsd ) -+maintains a cache of authentication and authorization information which -+is used to identify the source of each requent, and then what access -+permissions that source has to any local filesystem. When required -+information is not found in the cache, the server sends a request to -+.B mountd -+to fill in the missing information. Mountd uses a table of information -+stored in -+.B /var/lib/nfs/etab -+and maintained by -+.BR exportfs (8), -+possibly based on the contents of -+.BR exports (5), -+to respond to each request. - .SS Mounting exported NFS File Systems - The NFS MOUNT protocol has several procedures. - The most important of these are -@@ -78,11 +78,69 @@ A client may continue accessing an export even after invoking UMNT. - If the client reboots without sending a UMNT request, stale entries - remain for that client in - .IR /var/lib/nfs/rmtab . -+.SS Mounting File Systems with NFSv4 -+Version 4 (and later) of NFS does not use a separate NFS MOUNT -+protocol. Instead mounting is performed using regular NFS requests -+handled by the NFS server in the Linux kernel -+.RI ( nfsd ). -+Consequently -+.I /var/lib/nfs/rmtab -+is not updated to reflect any NFSv4 activity. - .SH OPTIONS - .TP - .B \-d kind " or " \-\-debug kind - Turn on debugging. Valid kinds are: all, auth, call, general and parse. - .TP -+.BR \-l " or " \-\-log\-auth -+Enable logging of responses to authentication and access requests from -+nfsd. Each response is then cached by the kernel for 30 minutes (or as set by -+.B \-\-ttl -+below), and will be refreshed after 15 minutes (half the ttl time) if -+the relevant client remains active. -+Note that -+.B -l -+is equivalent to -+.B "-d auth" -+and so can be enabled in -+.B /etc/nfs.conf -+with -+.B "\[dq]debug = auth\[dq]" -+in the -+.B "[mountd]" -+section. -+.IP -+.B rpc.mountd -+will always log authentication responses to MOUNT requests when NFSv3 is -+used, but to get similar logs for NFSv4, this option is required. -+.TP -+.BR \-i " or " \-\-cache\-use\-ipaddr -+Normally each client IP address is matched against each host identifier -+(name, wildcard, netgroup etc) found in -+.B /etc/exports -+and a combined identity is formed from all matching identifiers. -+Often many clients will map to the same combined identity so performing -+this mapping reduces the number of distinct access details that the -+kernel needs to store. -+Specifying the -+.B \-i -+option suppresses this mapping so that access to each filesystem is -+requested and cached separately for each client IP address. Doing this -+can increase the burden of updating the cache slightly, but can make the -+log messages produced by the -+.B -l -+option easier to read. -+.TP -+.B \-T " or " \-\-ttl -+Provide a time-to-live (TTL) for cached information given to the kernel. -+The kernel will normally request an update if the information is needed -+after half of this time has expired. Increasing the provided number, -+which is in seconds, reduces the rate of cache update requests, and this -+is particularly noticeable when these requests are logged with -+.BR \-l . -+However increasing also means that changes to hostname to address -+mappings can take longer to be noticed. -+The default TTL is 1800 (30 minutes). -+.TP - .B \-F " or " \-\-foreground - Run in foreground (do not daemonize) - .TP -@@ -213,9 +271,11 @@ Values recognized in the - .B [mountd] - section include - .BR manage-gids , -+.BR cache\-use\-ipaddr , - .BR descriptors , - .BR port , - .BR threads , -+.BR ttl , - .BR reverse-lookup ", and" - .BR state-directory-path , - .B ha-callout -@@ -295,5 +355,9 @@ table of clients accessing server's exports - RFC 1094 - "NFS: Network File System Protocol Specification" - .br - RFC 1813 - "NFS Version 3 Protocol Specification" -+.br -+RFC 7530 - "Network File System (NFS) Version 4 Protocol" -+.br -+RFC 8881 - "Network File System (NFS) Version 4 Minor Version 1 Protocol" - .SH AUTHOR - Olaf Kirch, H. J. Lu, G. Allan Morris III, and a host of others. -diff --git a/utils/mountd/svc_run.c b/utils/mountd/svc_run.c -index 41b96d7f..167b9757 100644 ---- a/utils/mountd/svc_run.c -+++ b/utils/mountd/svc_run.c -@@ -56,10 +56,9 @@ - #ifdef HAVE_LIBTIRPC - #include - #endif -+#include "export.h" - - void my_svc_run(void); --void cache_set_fds(fd_set *fdset); --int cache_process_req(fd_set *readfds); - - #if defined(__GLIBC__) && LONG_MAX != INT_MAX - /* bug in glibc 2.3.6 and earlier, we need -@@ -101,6 +100,7 @@ my_svc_run(void) - - readfds = svc_fdset; - cache_set_fds(&readfds); -+ v4clients_set_fds(&readfds); - - selret = select(FD_SETSIZE, &readfds, - (void *) 0, (void *) 0, (struct timeval *) 0); -@@ -116,6 +116,7 @@ my_svc_run(void) - - default: - selret -= cache_process_req(&readfds); -+ selret -= v4clients_process(&readfds); - if (selret) - svc_getreqset(&readfds); - }