From 368cd44bb63211edb018c8215ab7bd541c634572 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Thu, 19 Jan 2017 14:49:27 -0500 Subject: [PATCH] Added back the nfs-config service for backwards compatibility Signed-off-by: Steve Dickson --- nfs-utils-1.3.4-rc4.patch | 1591 ------------------ nfs-utils-1.3.4-rc5.patch | 2188 ------------------------ nfs-utils-1.3.4-rc6.patch | 2647 ------------------------------ nfs-utils-1.3.5-rc2.patch | 583 ------- nfs-utils-1.3.5-rc3.patch | 929 ----------- nfs-utils-2.1.1-nfs-config.patch | 202 +++ nfs-utils.spec | 12 +- nfs.sysconfig | 3 - 8 files changed, 209 insertions(+), 7946 deletions(-) delete mode 100644 nfs-utils-1.3.4-rc4.patch delete mode 100644 nfs-utils-1.3.4-rc5.patch delete mode 100644 nfs-utils-1.3.4-rc6.patch delete mode 100644 nfs-utils-1.3.5-rc2.patch delete mode 100644 nfs-utils-1.3.5-rc3.patch create mode 100644 nfs-utils-2.1.1-nfs-config.patch diff --git a/nfs-utils-1.3.4-rc4.patch b/nfs-utils-1.3.4-rc4.patch deleted file mode 100644 index d86d400..0000000 --- a/nfs-utils-1.3.4-rc4.patch +++ /dev/null @@ -1,1591 +0,0 @@ -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index b7de636..27368ff 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -20,6 +20,12 @@ AC_DEFUN([AC_LIBTIRPC], [ - [Define to 1 if your rpcsec library provides authgss_free_private_data])],, - [${LIBS}])]) - -+ AS_IF([test -n "${LIBTIRPC}"], -+ [AC_CHECK_LIB([tirpc], [libtirpc_set_debug], -+ [AC_DEFINE([HAVE_LIBTIRPC_SET_DEBUG], [1], -+ [Define to 1 if your tirpc library provides libtirpc_set_debug])],, -+ [${LIBS}])]) -+ - AC_SUBST([AM_CPPFLAGS]) - AC_SUBST(LIBTIRPC) - -diff --git a/support/export/client.c b/support/export/client.c -index 95156f0..2346f99 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -639,7 +639,7 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - const char *netgroup = clp->m_hostname + 1; - struct addrinfo *tmp = NULL; - struct hostent *hp; -- char *dot, *hname; -+ char *dot, *hname, *ip; - int i, match; - - match = 0; -@@ -686,6 +686,18 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - } - } - -+ /* check whether the IP itself is in the netgroup */ -+ ip = calloc(INET6_ADDRSTRLEN, 1); -+ if (inet_ntop(ai->ai_family, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, INET6_ADDRSTRLEN) == ip) { -+ if (innetgr(netgroup, ip, NULL, NULL)) { -+ free(hname); -+ hname = ip; -+ match = 1; -+ goto out; -+ } -+ } -+ free(ip); -+ - /* Okay, strip off the domain (if we have one) */ - dot = strchr(hname, '.'); - if (dot == NULL) -diff --git a/support/export/hostname.c b/support/export/hostname.c -index 169baa5..94e98a5 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -69,7 +69,7 @@ host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) - - memset(buf, 0, buflen); - -- if (sin->sin_family != AF_INET) -+ if (sin->sin_family != AF_INET) { - (void)strncpy(buf, "bad family", buflen - 1); - return buf; - } -@@ -134,12 +134,14 @@ host_pton(const char *paddr) - break; - } - return ai; -+ case EAI_NONAME: -+ break; - case EAI_SYSTEM: -- xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", -+ xlog(L_WARNING, "%s: failed to convert %s: (%d) %m", - __func__, paddr, errno); - break; - default: -- xlog(D_GENERAL, "%s: failed to convert %s: %s", -+ xlog(L_WARNING, "%s: failed to convert %s: %s", - __func__, paddr, gai_strerror(error)); - break; - } -diff --git a/support/include/ha-callout.h b/support/include/ha-callout.h -index 1164336..a454bdb 100644 ---- a/support/include/ha-callout.h -+++ b/support/include/ha-callout.h -@@ -47,7 +47,7 @@ ha_callout(char *event, char *arg1, char *arg2, int arg3) - arg3 < 0 ? NULL : buf, - NULL); - perror("execl"); -- exit(2); -+ _exit(2); - case -1: perror("fork"); - break; - default: pid = waitpid(pid, &ret, 0); -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index c9a13cb..ddd71ac 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -176,6 +176,9 @@ size_t strlcpy(char *, const char *, size_t); - ssize_t atomicio(ssize_t (*f) (int, void*, size_t), - int, void *, size_t); - -+#ifdef HAVE_LIBTIRPC_SET_DEBUG -+void libtirpc_set_debug(char *name, int level, int use_stderr); -+#endif - - #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) - -diff --git a/support/nfs/closeall.c b/support/nfs/closeall.c -index 38fb162..a69bf35 100644 ---- a/support/nfs/closeall.c -+++ b/support/nfs/closeall.c -@@ -31,6 +31,7 @@ closeall(int min) - } else { - int fd = sysconf(_SC_OPEN_MAX); - while (--fd >= min) -- (void) close(fd); -+ if(fd >= 0) -+ (void) close(fd); - } - } -diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c -index 3391eff..343e80b 100644 ---- a/support/nfs/mydaemon.c -+++ b/support/nfs/mydaemon.c -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - #include - - #include "nfslib.h" -@@ -122,6 +123,7 @@ daemon_init(bool fg) - dup2(tempfd, 0); - dup2(tempfd, 1); - dup2(tempfd, 2); -+ closelog(); - dup2(pipefds[1], 3); - pipefds[1] = 3; - closeall(4); -diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c -index 2900d18..bdf6d2f 100644 ---- a/support/nfs/rpc_socket.c -+++ b/support/nfs/rpc_socket.c -@@ -185,7 +185,7 @@ static int nfs_connect_nb(const int fd, const struct sockaddr *sap, - * use it later. - */ - ret = connect(fd, sap, salen); -- if (ret < 0 && errno != EINPROGRESS) { -+ if (ret < 0 && errno != EINPROGRESS && errno != EINTR) { - ret = -1; - goto done; - } -@@ -197,10 +197,16 @@ static int nfs_connect_nb(const int fd, const struct sockaddr *sap, - FD_ZERO(&rset); - FD_SET(fd, &rset); - -- ret = select(fd + 1, NULL, &rset, NULL, timeout); -- if (ret <= 0) { -- if (ret == 0) -- errno = ETIMEDOUT; -+ while ((ret = select(fd + 1, NULL, &rset, NULL, timeout)) < 0) { -+ if (errno != EINTR) { -+ ret = -1; -+ goto done; -+ } else { -+ continue; -+ } -+ } -+ if (ret == 0) { -+ errno = ETIMEDOUT; - ret = -1; - goto done; - } -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index 5cb5ff6..ef7ff05 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -133,7 +133,7 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - hint.ai_family = AF_INET6; - #endif /* IPV6_SUPPORTED */ - else { -- xlog(D_GENERAL, "Unrecognized bind address family: %s", -+ xlog(L_ERROR, "Unrecognized bind address family: %s", - nconf->nc_protofmly); - return NULL; - } -@@ -143,7 +143,7 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - else if (strcmp(nconf->nc_proto, NC_TCP) == 0) - hint.ai_protocol = (int)IPPROTO_TCP; - else { -- xlog(D_GENERAL, "Unrecognized bind address protocol: %s", -+ xlog(L_ERROR, "Unrecognized bind address protocol: %s", - nconf->nc_proto); - return NULL; - } -@@ -275,7 +275,7 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0); - freeaddrinfo(ai); - if (xprt == NULL) { -- xlog(D_GENERAL, "Failed to create listener xprt " -+ xlog(L_ERROR, "Failed to create listener xprt " - "(%s, %u, %s)", name, version, nconf->nc_netid); - return 0; - } -@@ -286,10 +286,12 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - return 0; - } - -+ rpc_createerr.cf_stat = rpc_createerr.cf_error.re_errno = 0; - if (!svc_reg(xprt, program, version, dispatch, nconf)) { - /* svc_reg(3) destroys @xprt in this case */ -- xlog(D_GENERAL, "Failed to register (%s, %u, %s)", -- name, version, nconf->nc_netid); -+ xlog(L_ERROR, "Failed to register (%s, %u, %s): %s", -+ name, version, nconf->nc_netid, -+ clnt_spcreateerror("svc_reg() err")); - return 0; - } - -diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c -index 99321e7..1fa0d15 100644 ---- a/support/nfs/svc_socket.c -+++ b/support/nfs/svc_socket.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include "xlog.h" - - #include "config.h" - -@@ -99,9 +100,9 @@ svcsock_nonblock(int sock) - * connection. - */ - if ((flags = fcntl(sock, F_GETFL)) < 0) -- perror(_("svc_socket: can't get socket flags")); -+ xlog(L_ERROR, "svc_socket: can't get socket flags: %m"); - else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -- perror(_("svc_socket: can't set socket flags")); -+ xlog(L_ERROR, "svc_socket: can't set socket flags: %m"); - else - return sock; - -@@ -119,7 +120,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - - if ((sock = __socket (AF_INET, type, protocol)) < 0) - { -- perror (_("svc_socket: socket creation problem")); -+ xlog(L_ERROR, "svc_socket: socket creation problem: %m"); - return sock; - } - -@@ -130,7 +131,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - sizeof (ret)); - if (ret < 0) - { -- perror (_("svc_socket: socket reuse problem")); -+ xlog(L_ERROR, "svc_socket: socket reuse problem: %m"); - return ret; - } - } -@@ -141,7 +142,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - - if (bind(sock, (struct sockaddr *) &addr, len) < 0) - { -- perror (_("svc_socket: bind problem")); -+ xlog(L_ERROR, "svc_socket: bind problem: %m"); - (void) __close(sock); - sock = -1; - } -diff --git a/support/nsm/file.c b/support/nsm/file.c -index 4711c2c..7a8b504 100644 ---- a/support/nsm/file.c -+++ b/support/nsm/file.c -@@ -536,7 +536,8 @@ nsm_get_state(_Bool update) - state++; - - update: -- (void)close(fd); -+ if(fd >= 0) -+ (void)close(fd); - - if (update) { - state += 2; -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -index 0331926..03f96e9 100644 ---- a/systemd/Makefile.am -+++ b/systemd/Makefile.am -@@ -28,9 +28,13 @@ endif - if CONFIG_GSS - unit_files += \ - auth-rpcgss-module.service \ -- rpc-gssd.service \ -+ rpc-gssd.service -+ -+if CONFIG_SVCGSS -+unit_files += \ - rpc-svcgssd.service - endif -+endif - - EXTRA_DIST = $(unit_files) - -diff --git a/systemd/nfs-config.service b/systemd/nfs-config.service -index 7f65305..4b206b5 100644 ---- a/systemd/nfs-config.service -+++ b/systemd/nfs-config.service -@@ -5,5 +5,9 @@ DefaultDependencies=no - - [Service] - Type=oneshot --RemainAfterExit=yes -+# 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=/usr/lib/systemd/scripts/nfs-utils_env.sh -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 12b02f2..317e5d6 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -1,7 +1,7 @@ - [Unit] - Description=NFS server and services - DefaultDependencies=no --Requires= network.target proc-fs-nfsd.mount rpcbind.service -+Requires= network.target proc-fs-nfsd.mount rpcbind.target - Requires= nfs-mountd.service - Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service -diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service -index 14604d7..f16ea42 100644 ---- a/systemd/rpc-statd.service -+++ b/systemd/rpc-statd.service -@@ -3,7 +3,7 @@ Description=NFS status monitor for NFSv2/3 locking. - DefaultDependencies=no - Conflicts=umount.target - Requires=nss-lookup.target rpcbind.target --After=network.target nss-lookup.target rpcbind.target -+After=network.target nss-lookup.target rpcbind.service - - PartOf=nfs-utils.service - -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 011bb42..4ca4bc4 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -150,6 +150,8 @@ Nfsv3ops = [ - 'COMMIT' - ] - -+# This list should be kept in-sync with the NFSPROC4_CLNT_* enum in -+# include/linux/nfs4.h in the kernel. - Nfsv4ops = [ - 'NULL', - 'READ', -@@ -204,7 +206,12 @@ Nfsv4ops = [ - 'FREE_STATEID', - 'GETDEVICELIST', - 'BIND_CONN_TO_SESSION', -- 'DESTROY_CLIENTID' -+ 'DESTROY_CLIENTID', -+ 'SEEK', -+ 'ALLOCATE', -+ 'DEALLOCATE', -+ 'LAYOUTSTATS', -+ 'CLONE' - ] - - class DeviceData: -@@ -563,7 +570,10 @@ class DeviceData: - for the nfsstat command. - """ - for op in new_stats.__rpc_data['ops']: -- self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) -+ try: -+ self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) -+ except KeyError: -+ continue - - def __print_rpc_op_stats(self, op, sample_time): - """Print generic stats for one RPC op -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index b52afe2..b010628 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -427,7 +427,10 @@ void sig_die(int signal) - BL_LOG_ERR("exit on signal(%d)\n", signal); - exit(1); - } -- -+static void usage(void) -+{ -+ fprintf(stderr, "Usage: blkmapd [-hdf]\n" ); -+} - /* Daemon */ - int main(int argc, char **argv) - { -@@ -435,7 +438,7 @@ int main(int argc, char **argv) - struct stat statbuf; - char pidbuf[64]; - -- while ((opt = getopt(argc, argv, "df")) != -1) { -+ while ((opt = getopt(argc, argv, "hdf")) != -1) { - switch (opt) { - case 'd': - dflag = 1; -@@ -443,6 +446,13 @@ int main(int argc, char **argv) - case 'f': - fg = 1; - break; -+ case 'h': -+ usage(); -+ exit(0); -+ default: -+ usage(); -+ exit(1); -+ - } - } - -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 8758231..a9151ff 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -405,8 +405,17 @@ unexportfs_parsed(char *hname, char *path, int verbose) - hname = ai->ai_canonname; - } - -+ /* -+ * It's possible the specified path ends with a '/'. But -+ * the entry from exportlist won't has the trailing '/', -+ * so need to deal with it. -+ */ -+ size_t nlen = strlen(path); -+ while (path[nlen - 1] == '/') -+ nlen--; -+ - for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { -- if (path && strcmp(path, exp->m_export.e_path)) -+ if (path && strncmp(path, exp->m_export.e_path, nlen)) - continue; - if (htype != exp->m_client->m_type) - continue; -@@ -499,9 +508,10 @@ unexportfs(char *arg, int verbose) - - static int can_test(void) - { -- char buf[1024]; -+ char buf[1024] = { 0 }; - int fd; - int n; -+ size_t bufsiz = sizeof(buf); - - fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); - if (fd < 0) -@@ -514,9 +524,9 @@ static int can_test(void) - * commit 2f74f972 (sunrpc: prepare NFS for 2038). - */ - if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS) -- sprintf(buf, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); -+ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); - else -- sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); -+ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); - - n = write(fd, buf, strlen(buf)); - close(fd); -@@ -532,7 +542,8 @@ static int can_test(void) - - static int test_export(char *path, int with_fsid) - { -- char buf[1024]; -+ /* beside max path, buf size should take protocol str into account */ -+ char buf[NFS_MAXPATHLEN+1+64] = { 0 }; - char *bp = buf; - int len = sizeof(buf); - int fd, n; -@@ -758,7 +769,8 @@ dumpopt(char c, char *fmt, ...) - static void - dump(int verbose, int export_format) - { -- char buf[1024]; -+ /* buf[] size should >= sizeof(struct exportent->e_path) */ -+ char buf[NFS_MAXPATHLEN+1] = { 0 }; - char *bp; - int len; - nfs_export *exp; -diff --git a/utils/gssd/context_heimdal.c b/utils/gssd/context_heimdal.c -index 1e8738a..d07103b 100644 ---- a/utils/gssd/context_heimdal.c -+++ b/utils/gssd/context_heimdal.c -@@ -260,7 +260,7 @@ serialize_krb5_ctx(gss_ctx_id_t *_ctx, gss_buffer_desc *buf, int32_t *endtime) - if (write_heimdal_seq_key(&p, end, ctx)) goto out_err; - - buf->length = p - (char *)buf->value; -- printerr(2, "serialize_krb5_ctx: returning buffer " -+ printerr(4, "serialize_krb5_ctx: returning buffer " - "with %d bytes\n", buf->length); - - return 0; -diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index badbe88..5d77c21 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -206,7 +206,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, - if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; - - /* Protocol 0 here implies DES3 or RC4 */ -- printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); -+ printerr(4, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); - if (lctx->protocol == 0) { - enctype = lctx->rfc1964_kd.ctx_key.type; - keysize = lctx->rfc1964_kd.ctx_key.length; -@@ -219,7 +219,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, - keysize = lctx->cfx_kd.ctx_key.length; - } - } -- printerr(2, "%s: serializing key with enctype %d and size %d\n", -+ printerr(4, "%s: serializing key with enctype %d and size %d\n", - __FUNCTION__, enctype, keysize); - - if (WRITE_BYTES(&p, end, enctype)) goto out_err; -@@ -265,7 +265,7 @@ serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime) - gss_krb5_lucid_context_v1_t *lctx = 0; - int retcode = 0; - -- printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); -+ printerr(4, "DEBUG: %s: lucid version!\n", __FUNCTION__); - maj_stat = gss_export_lucid_sec_context(&min_stat, ctx, - 1, &return_ctx); - if (maj_stat != GSS_S_COMPLETE) { -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index e480349..7ba27b1 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -400,8 +400,9 @@ gssd_get_clnt(struct topdir *tdi, const char *name) - - clp->wd = inotify_add_watch(inotify_fd, clp->relpath, IN_CREATE | IN_DELETE); - if (clp->wd < 0) { -- printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", -- clp->relpath, strerror(errno)); -+ if (errno != ENOENT) -+ printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", -+ clp->relpath, strerror(errno)); - goto out; - } - -@@ -556,7 +557,7 @@ gssd_scan_topdir(const char *name) - if (clp->scanned) - continue; - -- printerr(2, "destroying client %s\n", clp->relpath); -+ printerr(3, "destroying client %s\n", clp->relpath); - saveprev = clp->list.tqe_prev; - TAILQ_REMOVE(&tdi->clnt_list, clp, list); - gssd_destroy_client(clp); -@@ -716,7 +717,7 @@ gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data)) - - found: - if (!tdi) { -- printerr(1, "inotify event for unknown wd!!! - " -+ printerr(5, "inotify event for unknown wd!!! - " - "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", - ev->wd, ev->len > 0 ? ev->name : "", ev->mask); - rescan = true; -@@ -820,7 +821,7 @@ main(int argc, char *argv[]) - * the results of getpw*. - */ - if (setenv("HOME", "/", 1)) { -- printerr(1, "Unable to set $HOME: %s\n", strerror(errno)); -+ printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); - exit(1); - } - -@@ -869,6 +870,13 @@ main(int argc, char *argv[]) - if (verbosity && rpc_verbosity == 0) - rpc_verbosity = verbosity; - authgss_set_debug_level(rpc_verbosity); -+#elif HAVE_LIBTIRPC_SET_DEBUG -+ /* -+ * Only set the libtirpc debug level if explicitly requested via -r... -+ * gssd is chatty enough as it is. -+ */ -+ if (rpc_verbosity > 0) -+ libtirpc_set_debug(progname, rpc_verbosity, fg); - #else - if (rpc_verbosity > 0) - printerr(0, "Warning: rpcsec_gss library does not " -@@ -884,19 +892,19 @@ main(int argc, char *argv[]) - - pipefs_dir = opendir(pipefs_path); - if (!pipefs_dir) { -- printerr(1, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); -+ printerr(0, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); - exit(EXIT_FAILURE); - } - - pipefs_fd = dirfd(pipefs_dir); - if (fchdir(pipefs_fd)) { -- printerr(1, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); -+ printerr(0, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); - exit(EXIT_FAILURE); - } - - inotify_fd = inotify_init1(IN_NONBLOCK); - if (inotify_fd == -1) { -- printerr(1, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); -+ printerr(0, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - -@@ -913,7 +921,7 @@ main(int argc, char *argv[]) - - event_dispatch(); - -- printerr(1, "ERROR: event_dispatch() returned!\n"); -+ printerr(0, "ERROR: event_dispatch() returned!\n"); - return EXIT_FAILURE; - } - -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 11168b2..2dd06a7 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -150,7 +150,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - unsigned int timeout = context_timeout; - unsigned int buf_size = 0; - -- printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", -+ printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", - 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 + -@@ -189,7 +189,7 @@ do_error_downcall(int k5_fd, uid_t uid, int err) - unsigned int timeout = 0; - int zero = 0; - -- printerr(1, "doing error downcall\n"); -+ printerr(2, "doing error downcall\n"); - - if (WRITE_BYTES(&p, end, uid)) goto out_err; - if (WRITE_BYTES(&p, end, timeout)) goto out_err; -@@ -348,16 +348,9 @@ create_auth_rpc_client(struct clnt_info *clp, - printerr(2, "creating %s client for server %s\n", clp->protocol, - clp->servername); - -- if ((strcmp(clp->protocol, "tcp")) == 0) { -- protocol = IPPROTO_TCP; -- } else if ((strcmp(clp->protocol, "udp")) == 0) { -+ protocol = IPPROTO_TCP; -+ if ((strcmp(clp->protocol, "udp")) == 0) - protocol = IPPROTO_UDP; -- } else { -- printerr(0, "WARNING: unrecognized protocol, '%s', requested " -- "for connection to server %s for user with uid %d\n", -- clp->protocol, clp->servername, uid); -- goto out_fail; -- } - - switch (addr->sa_family) { - case AF_INET: -@@ -491,7 +484,7 @@ krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - char **dname; - int err, resp = -1; - -- printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", -+ printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n", - uid, tgtname); - - *chg_err = change_identity(uid); -@@ -538,7 +531,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - int nocache = 0; - int success = 0; - -- printerr(1, "krb5_use_machine_creds: uid %d tgtname %s\n", -+ printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n", - uid, tgtname); - - do { -@@ -564,7 +557,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - success++; - break; - } -- printerr(2, "WARNING: Failed to create machine krb5" -+ printerr(2, "WARNING: Failed to create machine krb5 " - "context with cred cache %s for server %s\n", - *ccname, clp->servername); - } -@@ -572,12 +565,13 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - if (!success) { - if(nocache == 0) { - nocache++; -- printerr(2, "WARNING: Machine cache prematurely" "expired or corrupted trying to" -- "recreate cache for server %s\n", -+ printerr(2, "WARNING: Machine cache prematurely " -+ "expired or corrupted trying to " -+ "recreate cache for server %s\n", - clp->servername); - } else { -- printerr(1, "WARNING: Failed to create machine" -- "krb5 context with any credentials" -+ printerr(1, "ERROR: Failed to create machine " -+ "krb5 context with any credentials " - "cache for server %s\n", - clp->servername); - goto out; -@@ -608,8 +602,6 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - gss_OID mech; - gss_buffer_desc acceptor = {0}; - -- printerr(1, "handling krb5 upcall (%s)\n", clp->relpath); -- - token.length = 0; - token.value = NULL; - memset(&pd, 0, sizeof(struct authgss_private_data)); -@@ -635,8 +627,6 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - * used for this case is not important. - * - */ -- printerr(2, "%s: service is '%s'\n", __func__, -- service ? service : ""); - if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && - service == NULL)) { - -@@ -650,7 +640,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - /* Child: fall through to rest of function */ - childpid = getpid(); - unsetenv("KRB5CCNAME"); -- printerr(1, "CHILD forked pid %d \n", childpid); -+ printerr(2, "CHILD forked pid %d \n", childpid); - break; - case -1: - /* fork() failed! */ -@@ -683,9 +673,7 @@ no_fork: - if (auth == NULL) - goto out_return_error; - } else { -- printerr(1, "WARNING: Failed to create krb5 context " -- "for user with uid %d for server %s\n", -- uid, clp->servername); -+ /* krb5_not_machine_creds logs the error */ - goto out_return_error; - } - } -@@ -716,7 +704,7 @@ no_fork: - * try to use it after this point. - */ - if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { -- printerr(0, "WARNING: Failed to serialize krb5 context for " -+ printerr(1, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for server %s\n", - uid, clp->servername); - goto out_return_error; -@@ -759,6 +747,8 @@ handle_krb5_upcall(struct clnt_info *clp) - return; - } - -+ printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath); -+ - process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL); - } - -@@ -775,8 +765,6 @@ handle_gssd_upcall(struct clnt_info *clp) - char *service = NULL; - char *enctypes = NULL; - -- printerr(1, "handling gssd upcall (%s)\n", clp->relpath); -- - lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf)); - if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { - printerr(0, "WARNING: handle_gssd_upcall: " -@@ -785,7 +773,7 @@ handle_gssd_upcall(struct clnt_info *clp) - } - lbuf[lbuflen-1] = 0; - -- printerr(2, "%s: '%s'\n", __func__, lbuf); -+ printerr(2, "\n%s: '%s' (%s)\n", __func__, lbuf, clp->relpath); - - for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) { - if (!strncmp(p, "mech=", strlen("mech="))) -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index ecf17a2..8dc64fe 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -356,7 +356,7 @@ gssd_get_single_krb5_cred(krb5_context context, - */ - now += 300; - if (ple->ccname && ple->endtime > now && !nocache) { -- printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", -+ printerr(3, "INFO: Credentials in CC '%s' are good until %d\n", - ple->ccname, ple->endtime); - code = 0; - goto out; -@@ -383,7 +383,7 @@ gssd_get_single_krb5_cred(krb5_context context, - "tickets. May have problems behind a NAT.\n"); - #ifdef TEST_SHORT_LIFETIME - /* set a short lifetime (for debugging only!) */ -- printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); -+ printerr(1, "WARNING: Using (debug) short machine cred lifetime!\n"); - krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60); - #endif - opts = init_opts; -@@ -451,8 +451,7 @@ gssd_get_single_krb5_cred(krb5_context context, - } - - code = 0; -- printerr(2, "Successfully obtained machine credentials for " -- "principal '%s' stored in ccache '%s'\n", pname, cc_name); -+ printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name); - out: - #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS - if (init_opts) -@@ -477,7 +476,7 @@ gssd_set_krb5_ccache_name(char *ccname) - #ifdef USE_GSS_KRB5_CCACHE_NAME - u_int maj_stat, min_stat; - -- printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n", -+ printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", - ccname); - maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL); - if (maj_stat != GSS_S_COMPLETE) { -@@ -492,7 +491,7 @@ gssd_set_krb5_ccache_name(char *ccname) - * function above for which there is no generic gssapi - * equivalent.) - */ -- printerr(2, "using environment variable to select krb5 ccache %s\n", -+ printerr(3, "using environment variable to select krb5 ccache %s\n", - ccname); - setenv("KRB5CCNAME", ccname, 1); - #endif -@@ -797,11 +796,11 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - char **realmnames = NULL; - char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; - char myhostad[NI_MAXHOST+1]; -- int i, j, retval; -+ int i, j, k, retval; - char *default_realm = NULL; - char *realm; - char *k5err = NULL; -- int tried_all = 0, tried_default = 0; -+ int tried_all = 0, tried_default = 0, tried_upper = 0; - krb5_principal princ; - const char *notsetstr = "not set"; - char *adhostoverride; -@@ -835,7 +834,6 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - strcpy(myhostad, myhostname); - for (i = 0; myhostad[i] != 0; ++i) { - if (myhostad[i] == '.') break; -- myhostad[i] = toupper(myhostad[i]); - } - myhostad[i] = '$'; - myhostad[i+1] = 0; -@@ -936,6 +934,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - k5err = gssd_k5_err_msg(context, code); - printerr(3, "%s while getting keytab entry for '%s'\n", - k5err, spn); -+ /* -+ * We tried the active directory machine account -+ * with the hostname part as-is and failed... -+ * convert it to uppercase and try again before -+ * moving on to the svcname -+ */ -+ if (strcmp(svcnames[j],"$") == 0 && !tried_upper) { -+ for (k = 0; myhostad[k] != '$'; ++k) { -+ myhostad[k] = toupper(myhostad[k]); -+ } -+ j--; -+ tried_upper = 1; -+ } - } else { - printerr(3, "Success getting keytab entry for '%s'\n",spn); - retval = 0; -@@ -1081,8 +1092,8 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) - struct dirent *d; - int err, i, j; - -- printerr(2, "getting credentials for client with uid %u for " -- "server %s\n", uid, servername); -+ printerr(3, "looking for client creds with uid %u for " -+ "server %s in %s\n", uid, servername, dirpattern); - - for (i = 0, j = 0; dirpattern[i] != '\0'; i++) { - switch (dirpattern[i]) { -@@ -1398,16 +1409,21 @@ gssd_acquire_krb5_cred(gss_cred_id_t *gss_cred) - int - gssd_acquire_user_cred(gss_cred_id_t *gss_cred) - { -- OM_uint32 min_stat; -+ OM_uint32 maj_stat, min_stat; - int ret; - - ret = gssd_acquire_krb5_cred(gss_cred); - - /* force validation of cred to check for expiry */ - if (ret == 0) { -- if (gss_inquire_cred(&min_stat, *gss_cred, NULL, NULL, -- NULL, NULL) != GSS_S_COMPLETE) -- ret = -1; -+ maj_stat = gss_inquire_cred(&min_stat, *gss_cred, -+ NULL, NULL, NULL, NULL); -+ if (maj_stat != GSS_S_COMPLETE) { -+ if (get_verbosity() > 0) -+ pgsserr("gss_inquire_cred", -+ maj_stat, min_stat, &krb5oid); -+ ret = -1; -+ } - } - - return ret; -diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c -index f1b4347..0fe7c6d 100644 ---- a/utils/gssd/svcgssd.c -+++ b/utils/gssd/svcgssd.c -@@ -135,6 +135,13 @@ main(int argc, char *argv[]) - if (verbosity && rpc_verbosity == 0) - rpc_verbosity = verbosity; - authgss_set_debug_level(rpc_verbosity); -+#elif HAVE_LIBTIRPC_SET_DEBUG -+ /* -+ * Only set the libtirpc debug level if explicitly requested via -r... -+ * svcgssd is chatty enough as it is. -+ */ -+ if (rpc_verbosity > 0) -+ libtirpc_set_debug(progname, rpc_verbosity, fg); - #else - if (rpc_verbosity > 0) - printerr(0, "Warning: rpcsec_gss library does not " -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 689608a..f4e083a 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -199,6 +199,12 @@ flush_nfsd_idmap_cache(void) - return ret; - } - -+void usage(char *progname) -+{ -+ fprintf(stderr, "Usage: %s [-hfvCS] [-p path] [-c path]\n", -+ basename(progname)); -+} -+ - int - main(int argc, char **argv) - { -@@ -225,16 +231,18 @@ main(int argc, char **argv) - progname = argv[0]; - xlog_open(progname); - --#define GETOPTSTR "vfd:p:U:G:c:CS" -+#define GETOPTSTR "hvfd:p:U:G:c:CS" - opterr=0; /* Turn off error messages */ - while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { - if (opt == 'c') - conf_path = optarg; - if (opt == '?') { - if (strchr(GETOPTSTR, optopt)) -- errx(1, "'-%c' option requires an argument.", optopt); -+ warnx("'-%c' option requires an argument.", optopt); - else -- errx(1, "'-%c' is an invalid argument.", optopt); -+ warnx("'-%c' is an invalid argument.", optopt); -+ usage(progname); -+ exit(1); - } - } - optind = 1; -@@ -276,6 +284,9 @@ main(int argc, char **argv) - case 'S': - clientstart = 0; - break; -+ case 'h': -+ usage(progname); -+ exit(0); - default: - break; - } -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index c809f78..b9200c7 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -10,8 +10,11 @@ - .Sh SYNOPSIS - .\" For a program: program [-abc] file ... - .Nm rpc.idmapd --.Op Fl v -+.Op Fl h - .Op Fl f -+.Op Fl v -+.Op Fl C -+.Op Fl S - .Op Fl p Ar path - .Op Fl c Ar path - .Sh DESCRIPTION -@@ -32,6 +35,8 @@ program. - .Pp - The options are as follows: - .Bl -tag -width Ds_imagedir -+.It Fl h -+Display usage message. - .It Fl v - Increases the verbosity level (can be specified multiple times). - .It Fl f -diff --git a/utils/mount/network.c b/utils/mount/network.c -index b5ed850..7240ca7 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -92,6 +92,7 @@ static const char *nfs_version_opttbl[] = { - "v4", - "vers", - "nfsvers", -+ "minorversion", - NULL, - }; - -@@ -793,6 +794,7 @@ int start_statd(void) - if (stat(START_STATD, &stb) == 0) { - if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) { - int cnt = STATD_TIMEOUT * 10; -+ int status = 0; - const struct timespec ts = { - .tv_sec = 0, - .tv_nsec = 100000000, -@@ -807,7 +809,10 @@ int start_statd(void) - progname, strerror(errno)); - break; - default: /* parent */ -- waitpid(pid, NULL,0); -+ if (waitpid(pid, &status,0) == pid && -+ status == 0) -+ /* assume it worked */ -+ return 1; - break; - } - while (1) { -@@ -1272,7 +1277,11 @@ nfs_nfs_version(struct mount_options *options, struct nfs_version *version) - if (!(version->major = strtol(version_val, &cptr, 10))) - goto ret_error; - -- if (version->major < 4) -+ if (strcmp(nfs_version_opttbl[i], "minorversion") == 0) { -+ version->v_mode = V_SPECIFIC; -+ version->minor = version->major; -+ version->major = 4; -+ } else if (version->major < 4) - version->v_mode = V_SPECIFIC; - - if (*cptr == '.') { -@@ -1626,7 +1635,10 @@ int nfs_options2pmap(struct mount_options *options, - return 0; - if (!nfs_nfs_version(options, &version)) - return 0; -- nfs_pmap->pm_vers = version.major; -+ if (version.v_mode == V_DEFAULT) -+ nfs_pmap->pm_vers = 0; -+ else -+ nfs_pmap->pm_vers = version.major; - if (!nfs_nfs_protocol(options, &nfs_pmap->pm_prot)) - return 0; - if (!nfs_nfs_port(options, &nfs_pmap->pm_port)) -diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c -index d64b83d..0d3bcb9 100644 ---- a/utils/mount/parse_dev.c -+++ b/utils/mount/parse_dev.c -@@ -118,7 +118,8 @@ static int nfs_parse_simple_hostname(const char *dev, - if (pathname) { - *pathname = strndup(colon, path_len); - if (*pathname == NULL) { -- free(*hostname); -+ if (hostname) -+ free(*hostname); - return nfs_pdn_nomem_err(); - } - } -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index c8f5a6d..320dde2 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -841,6 +841,9 @@ check_result: - case EPROTONOSUPPORT: - /* A clear indication that the server or our - * client does not support NFS version 4 and minor */ -+ case EINVAL: -+ /* A less clear indication that our client -+ * does not support NFSv4 minor version. */ - if (mi->version.v_mode == V_GENERAL && - mi->version.minor == 0) - return result; -@@ -957,6 +960,15 @@ static int nfsmount_fg(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -+ if (errno == EBUSY) -+ /* The only cause of EBUSY is if exactly the desired -+ * filesystem is already mounted. That can arguably -+ * be seen as success. "mount -a" tries to optimise -+ * out this case but sometimes fails. Help it out -+ * by pretending everything is rosy -+ */ -+ return EX_SUCCESS; -+ - if (nfs_is_permanent_error(errno)) - break; - -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index 330cab5..894a7a5 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -85,7 +85,7 @@ auth_reload() - { - struct stat stb; - static ino_t last_inode; -- static int last_fd; -+ static int last_fd = -1; - static unsigned int counter; - int fd; - -@@ -93,11 +93,22 @@ auth_reload() - xlog(L_FATAL, "couldn't open %s", _PATH_ETAB); - } else if (fstat(fd, &stb) < 0) { - xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB); -- } else if (stb.st_ino == last_inode) { -+ close(fd); -+ } else if (last_fd != -1 && stb.st_ino == last_inode) { -+ /* We opened the etab file before, and its inode -+ * number hasn't changed since then. -+ */ - close(fd); - return counter; - } else { -- close(last_fd); -+ /* Need to process entries from the etab file. Close -+ * the file descriptor from the previous open (last_fd), -+ * and keep the current file descriptor open to prevent -+ * the file system reusing the current inode number -+ * (last_inode). -+ */ -+ if (last_fd != -1) -+ close(last_fd); - last_fd = fd; - last_inode = stb.st_ino; - } -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 9fe0f40..b584afc 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -794,9 +794,10 @@ main(int argc, char **argv) - } - - /* No more arguments allowed. */ -- if (optind != argc || !version_any()) -+ if (optind != argc || !version_any()) { -+ fprintf(stderr, "%s: No protocol versions specified!\n", progname); - usage(progname, 1); -- -+ } - if (chdir(state_dir)) { - fprintf(stderr, "%s: chdir(%s) failed: %s\n", - progname, state_dir, strerror(errno)); -@@ -910,7 +911,8 @@ usage(const char *prog, int n) - " [-o num|--descriptors num] [-f exports-file|--exports-file=file]\n" - " [-p|--port port] [-V version|--nfs-version version]\n" - " [-N version|--no-nfs-version version] [-n|--no-tcp]\n" --" [-H ha-callout-prog] [-s|--state-directory-path path]\n" --" [-g|--manage-gids] [-t num|--num-threads=num] [-u|--no-udp]\n", prog); -+" [-H ha-callout prog] [-r | --reverse-lookup]\n" -+" [-s|--state-directory-path path] [-g|--manage-gids]\n" -+" [-t num|--num-threads=num] [-u|--no-udp]\n", prog); - exit(n); - } -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index 7c5bfbe..66e3bba 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -115,10 +115,7 @@ must be invoked with the option - .B \-n " or " \-\-no-tcp - Don't advertise TCP for mount. - .TP --.B \-P --Ignored (compatibility with unfsd??). --.TP --.B \-p num " or " \-\-port num -+.B \-p num " or " \-P num " or " \-\-port num - Specifies the port number used for RPC listener sockets. - If this option is not specified, - .B rpc.mountd -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index a2b11d8..dcb430a 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -168,22 +168,22 @@ nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port) - continue; - } - -- xlog(D_GENERAL, "Creating %s %s socket.", family, proto); -- - /* open socket and prepare to hand it off to kernel */ - sockfd = socket(addr->ai_family, addr->ai_socktype, - addr->ai_protocol); - if (sockfd < 0) { -- if (errno == EAFNOSUPPORT) -- xlog(L_NOTICE, "address family %s not " -- "supported by protocol %s", -- family, proto); -- else -+ if (errno != EAFNOSUPPORT) { - xlog(L_ERROR, "unable to create %s %s socket: " - "errno %d (%m)", family, proto, errno); -- rc = errno; -- goto error; -+ rc = errno; -+ goto error; -+ } -+ addr = addr->ai_next; -+ continue; - } -+ -+ xlog(D_GENERAL, "Created %s %s socket.", family, proto); -+ - #ifdef IPV6_SUPPORTED - if (addr->ai_family == AF_INET6 && - setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) { -@@ -282,7 +282,7 @@ nfssvc_set_rdmaport(const char *port) - int fd; - - if (sv) -- nport = sv->s_port; -+ nport = ntohs(sv->s_port); - else { - char *ep; - nport = strtol(port, &ep, 10); -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 507193b..2abefe9 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -80,8 +80,9 @@ static int keyring_clear(const char *keyring) - - key = find_key_by_type_and_desc("keyring", keyring, 0); - if (key == -1) { -- xlog_err("'%s' keyring was not found.", keyring); -- return EXIT_FAILURE; -+ if (verbose) -+ xlog_warn("'%s' keyring was not found.", keyring); -+ return EXIT_SUCCESS; - } - - if (keyctl_clear(key) < 0) { -@@ -89,10 +90,9 @@ static int keyring_clear(const char *keyring) - (unsigned int)key); - return EXIT_FAILURE; - } -- -+ - if (verbose) - xlog_warn("'%s' cleared", keyring); -- - return EXIT_SUCCESS; - } - -@@ -404,6 +404,11 @@ int main(int argc, char **argv) - } - } - -+ if (geteuid() != 0) { -+ xlog_err("Must be run as root."); -+ return EXIT_FAILURE; -+ } -+ - if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF))) { - xlog_errno(rc, "Unable to create name to user id mappings."); - return EXIT_FAILURE; -@@ -423,9 +428,9 @@ int main(int argc, char **argv) - return keyring_clear(DEFAULT_KEYRING); - } - -- xlog_stderr(0); -+ xlog_stderr(verbose); - if ((argc - optind) != 2) { -- xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn("Bad arg count. Check /etc/request-key.conf"); - xlog_warn(usage, progname); - return EXIT_FAILURE; - } -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index 9f481db..8376347 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -31,8 +31,8 @@ enum { - SRVPROC3_SZ = 22, - CLTPROC3_SZ = 22, - SRVPROC4_SZ = 2, -- CLTPROC4_SZ = 49, -- SRVPROC4OPS_SZ = 59, -+ CLTPROC4_SZ = 59, -+ SRVPROC4OPS_SZ = 71, - }; - - static unsigned int srvproc2info[SRVPROC2_SZ+2], -@@ -127,19 +127,30 @@ static const char * nfscltproc4name[CLTPROC4_SZ] = { - "remove", "rename", "link", "symlink", "create", "pathconf", - "statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl", - "setacl", "fs_locations", -- "rel_lkowner", "secinfo", -+ "rel_lkowner", "secinfo", "fsid_present", - /* nfsv4.1 client ops */ - "exchange_id", -- "create_ses", -- "destroy_ses", -+ "create_session", -+ "destroy_session", - "sequence", -- "get_lease_t", -+ "get_lease_time", - "reclaim_comp", - "layoutget", - "getdevinfo", - "layoutcommit", - "layoutreturn", -- "getdevlist", -+ "secinfo_no", -+ "test_stateid", -+ "free_stateid", -+ "getdevicelist", -+ "bind_conn_to_ses", -+ "destroy_clientid", -+ /* nfsv4.2 client ops */ -+ "seek", -+ "allocate", -+ "deallocate", -+ "layoutstats", -+ "clone", - }; - - static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = { -@@ -170,6 +181,19 @@ static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = { - "want_deleg", - "destroy_clid", - "reclaim_comp", -+ /* nfsv4.2 server ops */ -+ "allocate", -+ "copy", -+ "copy_notify", -+ "deallocate", -+ "ioadvise", -+ "layouterror", -+ "layoutstats", -+ "offloadcancel", -+ "offloadstatus", -+ "readplus", -+ "seek", -+ "write_same", - }; - - #define LABEL_srvnet "Server packet stats:\n" -@@ -823,13 +847,13 @@ print_callstats(const char *hdr, const char **names, - total += info[i]; - if (!total) - total = 1; -- for (i = 0; i < nr; i += 6) { -- for (j = 0; j < 6 && i + j < nr; j++) -- printf("%-13s", names[i+j]); -+ for (i = 0; i < nr; i += 5) { -+ for (j = 0; j < 5 && i + j < nr; j++) -+ printf("%-17s", names[i+j]); - printf("\n"); -- for (j = 0; j < 6 && i + j < nr; j++) { -+ for (j = 0; j < 5 && i + j < nr; j++) { - pct = ((unsigned long long) info[i+j]*100)/total; -- printf("%-8u%3llu%% ", info[i+j], pct); -+ printf("%-8u%3llu%% ", info[i+j], pct); - } - printf("\n"); - } -diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c -index c61087c..8cccdb8 100644 ---- a/utils/statd/hostname.c -+++ b/utils/statd/hostname.c -@@ -180,9 +180,6 @@ get_nameinfo(const struct sockaddr *sap, - * Incoming hostnames are looked up to determine the canonical hostname, - * and incoming presentation addresses are converted to canonical - * hostnames. -- * -- * We won't monitor peers that don't have a reverse map. The canonical -- * name gives us a key for our monitor list. - */ - __attribute__((__malloc__)) - char * -@@ -207,7 +204,7 @@ statd_canonical_name(const char *hostname) - result = get_nameinfo(ai->ai_addr, ai->ai_addrlen, - buf, (socklen_t)sizeof(buf)); - freeaddrinfo(ai); -- if (!result) -+ if (!result || buf[0] == '\0') - /* OK to use presentation address, - * if no reverse map exists */ - return strdup(hostname); -diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c -index 286a5e2..368bd80 100644 ---- a/utils/statd/monitor.c -+++ b/utils/statd/monitor.c -@@ -72,6 +72,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - }; - char *dnsname = NULL; -+ int existing = 0; - - xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name); - -@@ -148,17 +149,26 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - if (statd_matchhostname(NL_MY_NAME(clnt), my_name) && - NL_MY_PROC(clnt) == id->my_proc && - NL_MY_PROG(clnt) == id->my_prog && -- NL_MY_VERS(clnt) == id->my_vers && -- memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) { -- /* Hey! We already know you guys! */ -- xlog(D_GENERAL, -- "Duplicate SM_MON request for %s " -- "from procedure on %s", -- mon_name, my_name); -+ NL_MY_VERS(clnt) == id->my_vers) { -+ if (memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE)) { -+ xlog(D_GENERAL, -+ "Received SM_MON request with new " -+ "cookie for %s from procedure on %s", -+ mon_name, my_name); -+ -+ existing = 1; -+ break; -+ } else { -+ /* Hey! We already know you guys! */ -+ xlog(D_GENERAL, -+ "Duplicate SM_MON request for %s " -+ "from procedure on %s", -+ mon_name, my_name); - -- /* But we'll let you pass anyway. */ -- free(dnsname); -- goto success; -+ /* But we'll let you pass anyway. */ -+ free(dnsname); -+ goto success; -+ } - } - clnt = NL_NEXT(clnt); - } -@@ -167,7 +177,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - * We're committed...ignoring errors. Let's hope that a malloc() - * doesn't fail. (I should probably fix this assumption.) - */ -- if (!(clnt = nlist_new(my_name, mon_name, 0))) { -+ if (!existing && !(clnt = nlist_new(my_name, mon_name, 0))) { - free(dnsname); - xlog_warn("out of memory"); - goto failure; -@@ -180,8 +190,11 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - clnt->dns_name = dnsname; - - /* -- * Now, Create file on stable storage for host. -+ * Now, Create file on stable storage for host, first deleting any -+ * existing records on file. - */ -+ nsm_delete_monitored_host(dnsname, mon_name, my_name); -+ - if (!nsm_insert_monitored_host(dnsname, - (struct sockaddr *)(char *)&my_addr, argp)) { - nlist_free(NULL, clnt); -@@ -190,7 +203,8 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - - /* PRC: do the HA callout: */ - ha_callout("add-client", mon_name, my_name, -1); -- nlist_insert(&rtnl, clnt); -+ if (!existing) -+ nlist_insert(&rtnl, clnt); - xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name); - success: - result.res_stat = STAT_SUCC; -diff --git a/utils/statd/rmtcall.c b/utils/statd/rmtcall.c -index 45c84f9..c4f6364 100644 ---- a/utils/statd/rmtcall.c -+++ b/utils/statd/rmtcall.c -@@ -113,7 +113,6 @@ statd_get_socket(void) - if (sockfd < 0) - return -1; - -- FD_SET(sockfd, &SVC_FDSET); - return sockfd; - } - -diff --git a/utils/statd/start-statd b/utils/statd/start-statd -index 14369e5..19e6eb2 100755 ---- a/utils/statd/start-statd -+++ b/utils/statd/start-statd -@@ -6,11 +6,19 @@ - # site. - PATH="/sbin:/usr/sbin:/bin:/usr/bin" - -+if [ -s /var/run/rpc.statd.pid ] && -+ [ 1`cat /var/run/rpc.statd.pid` -gt 1 ] && -+ kill -0 `cat /var/run/rpc.statd.pid` > /dev/null 2>&1 -+then -+ # statd already running - must have been slow to respond. -+ exit 0 -+fi - # First try systemd if it's installed. - if [ -d /run/systemd/system ]; then - # Quit only if the call worked. - systemctl start rpc-statd.service && exit - fi - -+cd / - # Fall back to launching it ourselves. - exec rpc.statd --no-notify -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 2b7a167..e5b4c98 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -247,6 +247,7 @@ int main (int argc, char **argv) - int port = 0, out_port = 0; - int nlm_udp = 0, nlm_tcp = 0; - struct rlimit rlim; -+ int notify_sockfd; - - /* Default: daemon mode, no other options */ - run_mode = 0; -@@ -437,7 +438,7 @@ int main (int argc, char **argv) - } - - /* Make sure we have a privilege port for calling into the kernel */ -- if (statd_get_socket() < 0) -+ if ((notify_sockfd = statd_get_socket()) < 0) - exit(1); - - /* If sm-notify didn't take all the state files, load -@@ -484,7 +485,7 @@ int main (int argc, char **argv) - * Handle incoming requests: SM_NOTIFY socket requests, as - * well as callbacks from lockd. - */ -- my_svc_run(); /* I rolled my own, Olaf made it better... */ -+ my_svc_run(notify_sockfd); /* I rolled my own, Olaf made it better... */ - - /* Only get here when simulating a crash so we should probably - * start sm-notify running again. As we have already dropped -diff --git a/utils/statd/statd.h b/utils/statd/statd.h -index a1d8035..231ac7e 100644 ---- a/utils/statd/statd.h -+++ b/utils/statd/statd.h -@@ -28,7 +28,7 @@ extern _Bool statd_present_address(const struct sockaddr *sap, char *buf, - __attribute__((__malloc__)) - extern char * statd_canonical_name(const char *hostname); - --extern void my_svc_run(void); -+extern void my_svc_run(int); - extern void notify_hosts(void); - extern void shuffle_dirs(void); - extern int statd_get_socket(void); -diff --git a/utils/statd/svc_run.c b/utils/statd/svc_run.c -index d98ecee..28c1ad6 100644 ---- a/utils/statd/svc_run.c -+++ b/utils/statd/svc_run.c -@@ -78,7 +78,7 @@ my_svc_exit(void) - * The heart of the server. A crib from libc for the most part... - */ - void --my_svc_run(void) -+my_svc_run(int sockfd) - { - FD_SET_TYPE readfds; - int selret; -@@ -96,6 +96,8 @@ my_svc_run(void) - } - - readfds = SVC_FDSET; -+ /* Set notify sockfd for waiting for reply */ -+ FD_SET(sockfd, &readfds); - if (notify) { - struct timeval tv; - -@@ -125,8 +127,10 @@ my_svc_run(void) - - default: - selret -= process_reply(&readfds); -- if (selret) -+ if (selret) { -+ FD_CLR(sockfd, &readfds); - svc_getreqset(&readfds); -+ } - } - } - } diff --git a/nfs-utils-1.3.4-rc5.patch b/nfs-utils-1.3.4-rc5.patch deleted file mode 100644 index 0778bce..0000000 --- a/nfs-utils-1.3.4-rc5.patch +++ /dev/null @@ -1,2188 +0,0 @@ -diff --git a/aclocal/kerberos5.m4 b/aclocal/kerberos5.m4 -index 0bf35d3..8a0f3e4 100644 ---- a/aclocal/kerberos5.m4 -+++ b/aclocal/kerberos5.m4 -@@ -43,15 +43,6 @@ AC_DEFUN([AC_KERBEROS_V5],[ - -f $dir/lib/libgssapi_krb5.so \) ; then - AC_DEFINE(HAVE_KRB5, 1, [Define this if you have MIT Kerberos libraries]) - KRBDIR="$dir" -- dnl If we are using MIT K5 1.3.1 and before, we *MUST* use the -- dnl private function (gss_krb5_ccache_name) to get correct -- dnl behavior of changing the ccache used by gssapi. -- dnl Starting in 1.3.2, we *DO NOT* want to use -- dnl gss_krb5_ccache_name, instead we want to set KRB5CCNAME -- dnl to get gssapi to use a different ccache -- if test $K5VERS -le 131; then -- AC_DEFINE(USE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the private function, gss_krb5_cache_name, must be used to tell the Kerberos library which credentials cache to use. Otherwise, this is done by setting the KRB5CCNAME environment variable]) -- fi - gssapi_lib=gssapi_krb5 - break - dnl The following ugly hack brought on by the split installation -@@ -92,8 +83,6 @@ AC_DEFUN([AC_KERBEROS_V5],[ - AC_DEFINE(HAVE_LUCID_CONTEXT_SUPPORT, 1, [Define this if the Kerberos GSS library supports gss_krb5_export_lucid_sec_context]), ,$KRBLIBS) - AC_CHECK_LIB($gssapi_lib, gss_krb5_set_allowable_enctypes, - AC_DEFINE(HAVE_SET_ALLOWABLE_ENCTYPES, 1, [Define this if the Kerberos GSS library supports gss_krb5_set_allowable_enctypes]), ,$KRBLIBS) -- AC_CHECK_LIB($gssapi_lib, gss_krb5_ccache_name, -- AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the Kerberos GSS library supports gss_krb5_ccache_name]), ,$KRBLIBS) - AC_CHECK_LIB($gssapi_lib, gss_krb5_free_lucid_sec_context, - AC_DEFINE(HAVE_GSS_KRB5_FREE_LUCID_SEC_CONTEXT, 1, [Define this if the Kerberos GSS library supports gss_krb5_free_lucid_sec_context]), ,$KRBLIBS) - -diff --git a/aclocal/libpthread.m4 b/aclocal/libpthread.m4 -new file mode 100644 -index 0000000..e87d2a0 ---- /dev/null -+++ b/aclocal/libpthread.m4 -@@ -0,0 +1,13 @@ -+dnl Checks for pthreads library and headers -+dnl -+AC_DEFUN([AC_LIBPTHREAD], [ -+ -+ dnl Check for library, but do not add -lpthreads to LIBS -+ AC_CHECK_LIB([pthread], [pthread_create], [LIBPTHREAD=-lpthread], -+ [AC_MSG_ERROR([libpthread not found.])]) -+ AC_SUBST(LIBPTHREAD) -+ -+ AC_CHECK_HEADERS([pthread.h], , -+ [AC_MSG_ERROR([libpthread headers not found.])]) -+ -+])dnl -diff --git a/aclocal/librpcsecgss.m4 b/aclocal/librpcsecgss.m4 -deleted file mode 100644 -index e833141..0000000 ---- a/aclocal/librpcsecgss.m4 -+++ /dev/null -@@ -1,21 +0,0 @@ --dnl Checks for rpcsecgss library and headers --dnl KRB5LIBS must be set before this function is invoked. --dnl --AC_DEFUN([AC_LIBRPCSECGSS], [ -- -- dnl libtirpc provides an rpcsecgss API -- if test "$enable_tirpc" = no; then -- -- dnl Check for library, but do not add -lrpcsecgss to LIBS -- AC_CHECK_LIB([rpcsecgss], [authgss_create_default], [librpcsecgss=1], -- [AC_MSG_ERROR([librpcsecgss not found.])]) -- -- AC_CHECK_LIB([rpcsecgss], [authgss_set_debug_level], -- [AC_DEFINE([HAVE_AUTHGSS_SET_DEBUG_LEVEL], 1, -- [Define to 1 if you have the `authgss_set_debug_level' function.])]) -- -- AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1, -- [Define to 1 if your rpcsec library provides authgss_free_private_data,]) -- fi -- --])dnl -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index b7de636..27368ff 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -20,6 +20,12 @@ AC_DEFUN([AC_LIBTIRPC], [ - [Define to 1 if your rpcsec library provides authgss_free_private_data])],, - [${LIBS}])]) - -+ AS_IF([test -n "${LIBTIRPC}"], -+ [AC_CHECK_LIB([tirpc], [libtirpc_set_debug], -+ [AC_DEFINE([HAVE_LIBTIRPC_SET_DEBUG], [1], -+ [Define to 1 if your tirpc library provides libtirpc_set_debug])],, -+ [${LIBS}])]) -+ - AC_SUBST([AM_CPPFLAGS]) - AC_SUBST(LIBTIRPC) - -diff --git a/configure.ac b/configure.ac -index 25d2ba4..1daf5b8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -382,8 +382,8 @@ if test "$enable_gss" = yes; then - dnl Check for Kerberos V5 - AC_KERBEROS_V5 - -- dnl Invoked after AC_KERBEROS_V5; AC_LIBRPCSECGSS needs to have KRBLIBS set -- AC_LIBRPCSECGSS -+ dnl Check for pthreads -+ AC_LIBPTHREAD - - dnl librpcsecgss already has a dependency on libgssapi, - dnl but we need to make sure we get the right version -diff --git a/support/export/client.c b/support/export/client.c -index 95156f0..2346f99 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -639,7 +639,7 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - const char *netgroup = clp->m_hostname + 1; - struct addrinfo *tmp = NULL; - struct hostent *hp; -- char *dot, *hname; -+ char *dot, *hname, *ip; - int i, match; - - match = 0; -@@ -686,6 +686,18 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - } - } - -+ /* check whether the IP itself is in the netgroup */ -+ ip = calloc(INET6_ADDRSTRLEN, 1); -+ if (inet_ntop(ai->ai_family, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, INET6_ADDRSTRLEN) == ip) { -+ if (innetgr(netgroup, ip, NULL, NULL)) { -+ free(hname); -+ hname = ip; -+ match = 1; -+ goto out; -+ } -+ } -+ free(ip); -+ - /* Okay, strip off the domain (if we have one) */ - dot = strchr(hname, '.'); - if (dot == NULL) -diff --git a/support/export/hostname.c b/support/export/hostname.c -index 169baa5..5c4c824 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -69,7 +69,7 @@ host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) - - memset(buf, 0, buflen); - -- if (sin->sin_family != AF_INET) -+ if (sin->sin_family != AF_INET) { - (void)strncpy(buf, "bad family", buflen - 1); - return buf; - } -@@ -134,12 +134,14 @@ host_pton(const char *paddr) - break; - } - return ai; -+ case EAI_NONAME: -+ break; - case EAI_SYSTEM: -- xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", -+ xlog(L_WARNING, "%s: failed to convert %s: (%d) %m", - __func__, paddr, errno); - break; - default: -- xlog(D_GENERAL, "%s: failed to convert %s: %s", -+ xlog(L_WARNING, "%s: failed to convert %s: %s", - __func__, paddr, gai_strerror(error)); - break; - } -@@ -228,7 +230,7 @@ host_canonname(const struct sockaddr *sap) - default: - (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), - NULL, 0, NI_NUMERICHOST); -- xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ xlog(D_PARSE, "%s: failed to resolve %s: %s", - __func__, buf, gai_strerror(error)); - return NULL; - } -diff --git a/support/include/ha-callout.h b/support/include/ha-callout.h -index 1164336..a454bdb 100644 ---- a/support/include/ha-callout.h -+++ b/support/include/ha-callout.h -@@ -47,7 +47,7 @@ ha_callout(char *event, char *arg1, char *arg2, int arg3) - arg3 < 0 ? NULL : buf, - NULL); - perror("execl"); -- exit(2); -+ _exit(2); - case -1: perror("fork"); - break; - default: pid = waitpid(pid, &ret, 0); -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index c9a13cb..ddd71ac 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -176,6 +176,9 @@ size_t strlcpy(char *, const char *, size_t); - ssize_t atomicio(ssize_t (*f) (int, void*, size_t), - int, void *, size_t); - -+#ifdef HAVE_LIBTIRPC_SET_DEBUG -+void libtirpc_set_debug(char *name, int level, int use_stderr); -+#endif - - #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) - -diff --git a/support/include/xcommon.h b/support/include/xcommon.h -index d1a4b18..23c9a13 100644 ---- a/support/include/xcommon.h -+++ b/support/include/xcommon.h -@@ -17,6 +17,12 @@ - #include - #include - -+#ifdef MAJOR_IN_MKDEV -+#include -+#elif defined(MAJOR_IN_SYSMACROS) -+#include -+#endif -+ - #define streq(s, t) (strcmp ((s), (t)) == 0) - - /* Functions in sundries.c that are used in mount.c and umount.c */ -diff --git a/support/nfs/closeall.c b/support/nfs/closeall.c -index 38fb162..a69bf35 100644 ---- a/support/nfs/closeall.c -+++ b/support/nfs/closeall.c -@@ -31,6 +31,7 @@ closeall(int min) - } else { - int fd = sysconf(_SC_OPEN_MAX); - while (--fd >= min) -- (void) close(fd); -+ if(fd >= 0) -+ (void) close(fd); - } - } -diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c -index 3391eff..343e80b 100644 ---- a/support/nfs/mydaemon.c -+++ b/support/nfs/mydaemon.c -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - #include - - #include "nfslib.h" -@@ -122,6 +123,7 @@ daemon_init(bool fg) - dup2(tempfd, 0); - dup2(tempfd, 1); - dup2(tempfd, 2); -+ closelog(); - dup2(pipefds[1], 3); - pipefds[1] = 3; - closeall(4); -diff --git a/support/nfs/nfsexport.c b/support/nfs/nfsexport.c -index afd7c90..4b13265 100644 ---- a/support/nfs/nfsexport.c -+++ b/support/nfs/nfsexport.c -@@ -19,6 +19,7 @@ - - #include "nfslib.h" - #include "misc.h" -+#include "xcommon.h" - - /* if /proc/net/rpc/... exists, then - * write to it, as that interface is more stable. -diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c -index 2900d18..bdf6d2f 100644 ---- a/support/nfs/rpc_socket.c -+++ b/support/nfs/rpc_socket.c -@@ -185,7 +185,7 @@ static int nfs_connect_nb(const int fd, const struct sockaddr *sap, - * use it later. - */ - ret = connect(fd, sap, salen); -- if (ret < 0 && errno != EINPROGRESS) { -+ if (ret < 0 && errno != EINPROGRESS && errno != EINTR) { - ret = -1; - goto done; - } -@@ -197,10 +197,16 @@ static int nfs_connect_nb(const int fd, const struct sockaddr *sap, - FD_ZERO(&rset); - FD_SET(fd, &rset); - -- ret = select(fd + 1, NULL, &rset, NULL, timeout); -- if (ret <= 0) { -- if (ret == 0) -- errno = ETIMEDOUT; -+ while ((ret = select(fd + 1, NULL, &rset, NULL, timeout)) < 0) { -+ if (errno != EINTR) { -+ ret = -1; -+ goto done; -+ } else { -+ continue; -+ } -+ } -+ if (ret == 0) { -+ errno = ETIMEDOUT; - ret = -1; - goto done; - } -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index 5cb5ff6..ef7ff05 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -133,7 +133,7 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - hint.ai_family = AF_INET6; - #endif /* IPV6_SUPPORTED */ - else { -- xlog(D_GENERAL, "Unrecognized bind address family: %s", -+ xlog(L_ERROR, "Unrecognized bind address family: %s", - nconf->nc_protofmly); - return NULL; - } -@@ -143,7 +143,7 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - else if (strcmp(nconf->nc_proto, NC_TCP) == 0) - hint.ai_protocol = (int)IPPROTO_TCP; - else { -- xlog(D_GENERAL, "Unrecognized bind address protocol: %s", -+ xlog(L_ERROR, "Unrecognized bind address protocol: %s", - nconf->nc_proto); - return NULL; - } -@@ -275,7 +275,7 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0); - freeaddrinfo(ai); - if (xprt == NULL) { -- xlog(D_GENERAL, "Failed to create listener xprt " -+ xlog(L_ERROR, "Failed to create listener xprt " - "(%s, %u, %s)", name, version, nconf->nc_netid); - return 0; - } -@@ -286,10 +286,12 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - return 0; - } - -+ rpc_createerr.cf_stat = rpc_createerr.cf_error.re_errno = 0; - if (!svc_reg(xprt, program, version, dispatch, nconf)) { - /* svc_reg(3) destroys @xprt in this case */ -- xlog(D_GENERAL, "Failed to register (%s, %u, %s)", -- name, version, nconf->nc_netid); -+ xlog(L_ERROR, "Failed to register (%s, %u, %s): %s", -+ name, version, nconf->nc_netid, -+ clnt_spcreateerror("svc_reg() err")); - return 0; - } - -diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c -index 99321e7..1fa0d15 100644 ---- a/support/nfs/svc_socket.c -+++ b/support/nfs/svc_socket.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include "xlog.h" - - #include "config.h" - -@@ -99,9 +100,9 @@ svcsock_nonblock(int sock) - * connection. - */ - if ((flags = fcntl(sock, F_GETFL)) < 0) -- perror(_("svc_socket: can't get socket flags")); -+ xlog(L_ERROR, "svc_socket: can't get socket flags: %m"); - else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -- perror(_("svc_socket: can't set socket flags")); -+ xlog(L_ERROR, "svc_socket: can't set socket flags: %m"); - else - return sock; - -@@ -119,7 +120,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - - if ((sock = __socket (AF_INET, type, protocol)) < 0) - { -- perror (_("svc_socket: socket creation problem")); -+ xlog(L_ERROR, "svc_socket: socket creation problem: %m"); - return sock; - } - -@@ -130,7 +131,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - sizeof (ret)); - if (ret < 0) - { -- perror (_("svc_socket: socket reuse problem")); -+ xlog(L_ERROR, "svc_socket: socket reuse problem: %m"); - return ret; - } - } -@@ -141,7 +142,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - - if (bind(sock, (struct sockaddr *) &addr, len) < 0) - { -- perror (_("svc_socket: bind problem")); -+ xlog(L_ERROR, "svc_socket: bind problem: %m"); - (void) __close(sock); - sock = -1; - } -diff --git a/support/nsm/file.c b/support/nsm/file.c -index 4711c2c..7a8b504 100644 ---- a/support/nsm/file.c -+++ b/support/nsm/file.c -@@ -536,7 +536,8 @@ nsm_get_state(_Bool update) - state++; - - update: -- (void)close(fd); -+ if(fd >= 0) -+ (void)close(fd); - - if (update) { - state += 2; -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -index 0331926..03f96e9 100644 ---- a/systemd/Makefile.am -+++ b/systemd/Makefile.am -@@ -28,9 +28,13 @@ endif - if CONFIG_GSS - unit_files += \ - auth-rpcgss-module.service \ -- rpc-gssd.service \ -+ rpc-gssd.service -+ -+if CONFIG_SVCGSS -+unit_files += \ - rpc-svcgssd.service - endif -+endif - - EXTRA_DIST = $(unit_files) - -diff --git a/systemd/README b/systemd/README -index bbd7790..7c43df8 100644 ---- a/systemd/README -+++ b/systemd/README -@@ -53,7 +53,7 @@ client and systemd cannot specify is two-pronged reverse dependency. - (i.e. stop this unit if none of these units are running) - - Distro specific commandline configuration can be provided by --installing a script /usr/lib/systemd/scripts/nfs-utils_env.sh -+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. -diff --git a/systemd/nfs-config.service b/systemd/nfs-config.service -index 7f65305..bd69e84 100644 ---- a/systemd/nfs-config.service -+++ b/systemd/nfs-config.service -@@ -5,5 +5,9 @@ DefaultDependencies=no - - [Service] - Type=oneshot --RemainAfterExit=yes --ExecStart=/usr/lib/systemd/scripts/nfs-utils_env.sh -+# 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=/usr/libexec/nfs-utils/nfs-utils_env.sh -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 12b02f2..2ccdc63 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -1,13 +1,14 @@ - [Unit] - Description=NFS server and services - DefaultDependencies=no --Requires= network.target proc-fs-nfsd.mount rpcbind.service -+Requires= network.target proc-fs-nfsd.mount - Requires= nfs-mountd.service -+Wants=rpcbind.socket - Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service - - After= local-fs.target --After= network.target proc-fs-nfsd.mount rpcbind.service nfs-mountd.service -+After= network.target proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service - After= nfs-idmapd.service rpc-statd.service - Before= rpc-statd-notify.service - -diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service -index 14604d7..a02f5c4 100644 ---- a/systemd/rpc-statd.service -+++ b/systemd/rpc-statd.service -@@ -2,8 +2,8 @@ - Description=NFS status monitor for NFSv2/3 locking. - DefaultDependencies=no - Conflicts=umount.target --Requires=nss-lookup.target rpcbind.target --After=network.target nss-lookup.target rpcbind.target -+Requires=nss-lookup.target rpcbind.socket -+After=network.target nss-lookup.target rpcbind.socket - - PartOf=nfs-utils.service - -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 011bb42..4ca4bc4 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -150,6 +150,8 @@ Nfsv3ops = [ - 'COMMIT' - ] - -+# This list should be kept in-sync with the NFSPROC4_CLNT_* enum in -+# include/linux/nfs4.h in the kernel. - Nfsv4ops = [ - 'NULL', - 'READ', -@@ -204,7 +206,12 @@ Nfsv4ops = [ - 'FREE_STATEID', - 'GETDEVICELIST', - 'BIND_CONN_TO_SESSION', -- 'DESTROY_CLIENTID' -+ 'DESTROY_CLIENTID', -+ 'SEEK', -+ 'ALLOCATE', -+ 'DEALLOCATE', -+ 'LAYOUTSTATS', -+ 'CLONE' - ] - - class DeviceData: -@@ -563,7 +570,10 @@ class DeviceData: - for the nfsstat command. - """ - for op in new_stats.__rpc_data['ops']: -- self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) -+ try: -+ self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) -+ except KeyError: -+ continue - - def __print_rpc_op_stats(self, op, sample_time): - """Print generic stats for one RPC op -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index b52afe2..052d582 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -51,6 +51,7 @@ - #include - - #include "device-discovery.h" -+#include "xcommon.h" - - #define EVENT_SIZE (sizeof(struct inotify_event)) - #define EVENT_BUFSIZE (1024 * EVENT_SIZE) -@@ -427,7 +428,10 @@ void sig_die(int signal) - BL_LOG_ERR("exit on signal(%d)\n", signal); - exit(1); - } -- -+static void usage(void) -+{ -+ fprintf(stderr, "Usage: blkmapd [-hdf]\n" ); -+} - /* Daemon */ - int main(int argc, char **argv) - { -@@ -435,7 +439,7 @@ int main(int argc, char **argv) - struct stat statbuf; - char pidbuf[64]; - -- while ((opt = getopt(argc, argv, "df")) != -1) { -+ while ((opt = getopt(argc, argv, "hdf")) != -1) { - switch (opt) { - case 'd': - dflag = 1; -@@ -443,6 +447,13 @@ int main(int argc, char **argv) - case 'f': - fg = 1; - break; -+ case 'h': -+ usage(); -+ exit(0); -+ default: -+ usage(); -+ exit(1); -+ - } - } - -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 8758231..5db348b 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -108,11 +108,14 @@ main(int argc, char **argv) - xlog_stderr(1); - xlog_syslog(0); - -- while ((c = getopt(argc, argv, "afhio:ruvs")) != EOF) { -+ while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) { - switch(c) { - case 'a': - f_all = 1; - break; -+ case 'd': -+ xlog_sconfig(optarg, 1); -+ break; - case 'f': - force_flush = 1; - break; -@@ -405,8 +408,17 @@ unexportfs_parsed(char *hname, char *path, int verbose) - hname = ai->ai_canonname; - } - -+ /* -+ * It's possible the specified path ends with a '/'. But -+ * the entry from exportlist won't has the trailing '/', -+ * so need to deal with it. -+ */ -+ size_t nlen = strlen(path); -+ while (path[nlen - 1] == '/') -+ nlen--; -+ - for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { -- if (path && strcmp(path, exp->m_export.e_path)) -+ if (path && strncmp(path, exp->m_export.e_path, nlen)) - continue; - if (htype != exp->m_client->m_type) - continue; -@@ -499,9 +511,10 @@ unexportfs(char *arg, int verbose) - - static int can_test(void) - { -- char buf[1024]; -+ char buf[1024] = { 0 }; - int fd; - int n; -+ size_t bufsiz = sizeof(buf); - - fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); - if (fd < 0) -@@ -514,9 +527,9 @@ static int can_test(void) - * commit 2f74f972 (sunrpc: prepare NFS for 2038). - */ - if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS) -- sprintf(buf, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); -+ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); - else -- sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); -+ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); - - n = write(fd, buf, strlen(buf)); - close(fd); -@@ -532,7 +545,8 @@ static int can_test(void) - - static int test_export(char *path, int with_fsid) - { -- char buf[1024]; -+ /* beside max path, buf size should take protocol str into account */ -+ char buf[NFS_MAXPATHLEN+1+64] = { 0 }; - char *bp = buf; - int len = sizeof(buf); - int fd, n; -@@ -758,7 +772,8 @@ dumpopt(char c, char *fmt, ...) - static void - dump(int verbose, int export_format) - { -- char buf[1024]; -+ /* buf[] size should >= sizeof(struct exportent->e_path) */ -+ char buf[NFS_MAXPATHLEN+1] = { 0 }; - char *bp; - int len; - nfs_export *exp; -@@ -866,6 +881,6 @@ error(nfs_export *exp, int err) - static void - usage(const char *progname, int n) - { -- fprintf(stderr, "usage: %s [-afhioruvs] [host:/path]\n", progname); -+ fprintf(stderr, "usage: %s [-adfhioruvs] [host:/path]\n", progname); - exit(n); - } -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 75d952a..fdf9260 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -88,6 +88,9 @@ appropriate export entry for the host given in - to be added to the kernel's export table. - .SH OPTIONS - .TP -+.B \-d kind " or " \-\-debug kind -+Turn on debugging. Valid kinds are: all, auth, call, general and parse. -+.TP - .B -a - Export or unexport all directories. - .TP -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index cb040b3..3f5f59a 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -49,7 +49,8 @@ gssd_LDADD = \ - $(RPCSECGSS_LIBS) \ - $(KRBLIBS) \ - $(GSSAPI_LIBS) \ -- $(LIBTIRPC) -+ $(LIBTIRPC) \ -+ $(LIBPTHREAD) - - gssd_LDFLAGS = \ - $(KRBLDFLAGS) -diff --git a/utils/gssd/context_heimdal.c b/utils/gssd/context_heimdal.c -index 1e8738a..d07103b 100644 ---- a/utils/gssd/context_heimdal.c -+++ b/utils/gssd/context_heimdal.c -@@ -260,7 +260,7 @@ serialize_krb5_ctx(gss_ctx_id_t *_ctx, gss_buffer_desc *buf, int32_t *endtime) - if (write_heimdal_seq_key(&p, end, ctx)) goto out_err; - - buf->length = p - (char *)buf->value; -- printerr(2, "serialize_krb5_ctx: returning buffer " -+ printerr(4, "serialize_krb5_ctx: returning buffer " - "with %d bytes\n", buf->length); - - return 0; -diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index badbe88..5d77c21 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -206,7 +206,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, - if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; - - /* Protocol 0 here implies DES3 or RC4 */ -- printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); -+ printerr(4, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); - if (lctx->protocol == 0) { - enctype = lctx->rfc1964_kd.ctx_key.type; - keysize = lctx->rfc1964_kd.ctx_key.length; -@@ -219,7 +219,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, - keysize = lctx->cfx_kd.ctx_key.length; - } - } -- printerr(2, "%s: serializing key with enctype %d and size %d\n", -+ printerr(4, "%s: serializing key with enctype %d and size %d\n", - __FUNCTION__, enctype, keysize); - - if (WRITE_BYTES(&p, end, enctype)) goto out_err; -@@ -265,7 +265,7 @@ serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime) - gss_krb5_lucid_context_v1_t *lctx = 0; - int retcode = 0; - -- printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); -+ printerr(4, "DEBUG: %s: lucid version!\n", __FUNCTION__); - maj_stat = gss_export_lucid_sec_context(&min_stat, ctx, - 1, &return_ctx); - if (maj_stat != GSS_S_COMPLETE) { -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index e480349..9bf7917 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -87,7 +87,9 @@ unsigned int rpc_timeout = 5; - char *preferred_realm = NULL; - /* Avoid DNS reverse lookups on server names */ - static bool avoid_dns = true; -- -+int thread_started = false; -+pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER; -+pthread_cond_t pcond = PTHREAD_COND_INITIALIZER; - - TAILQ_HEAD(topdir_list_head, topdir) topdir_list; - -@@ -361,20 +363,54 @@ gssd_destroy_client(struct clnt_info *clp) - - static void gssd_scan(void); - -+static inline void -+wait_for_child_and_detach(pthread_t th) -+{ -+ pthread_mutex_lock(&pmutex); -+ while (!thread_started) -+ pthread_cond_wait(&pcond, &pmutex); -+ thread_started = false; -+ pthread_mutex_unlock(&pmutex); -+ pthread_detach(th); -+} -+ -+/* For each upcall create a thread, detach from the main process so that -+ * resources are released back into the system without the need for a join. -+ * We need to wait for the child thread to start and consume the event from -+ * the file descriptor. -+ */ - static void - gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) - { - struct clnt_info *clp = data; -- -- handle_gssd_upcall(clp); -+ pthread_t th; -+ int ret; -+ -+ ret = pthread_create(&th, NULL, (void *)handle_gssd_upcall, -+ (void *)clp); -+ if (ret != 0) { -+ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n", -+ ret, strerror(errno)); -+ return; -+ } -+ wait_for_child_and_detach(th); - } - - static void - gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) - { - struct clnt_info *clp = data; -- -- handle_krb5_upcall(clp); -+ pthread_t th; -+ int ret; -+ -+ ret = pthread_create(&th, NULL, (void *)handle_krb5_upcall, -+ (void *)clp); -+ if (ret != 0) { -+ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n", -+ ret, strerror(errno)); -+ return; -+ } -+ wait_for_child_and_detach(th); - } - - static struct clnt_info * -@@ -400,8 +436,9 @@ gssd_get_clnt(struct topdir *tdi, const char *name) - - clp->wd = inotify_add_watch(inotify_fd, clp->relpath, IN_CREATE | IN_DELETE); - if (clp->wd < 0) { -- printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", -- clp->relpath, strerror(errno)); -+ if (errno != ENOENT) -+ printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", -+ clp->relpath, strerror(errno)); - goto out; - } - -@@ -556,7 +593,7 @@ gssd_scan_topdir(const char *name) - if (clp->scanned) - continue; - -- printerr(2, "destroying client %s\n", clp->relpath); -+ printerr(3, "destroying client %s\n", clp->relpath); - saveprev = clp->list.tqe_prev; - TAILQ_REMOVE(&tdi->clnt_list, clp, list); - gssd_destroy_client(clp); -@@ -716,7 +753,7 @@ gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data)) - - found: - if (!tdi) { -- printerr(1, "inotify event for unknown wd!!! - " -+ printerr(5, "inotify event for unknown wd!!! - " - "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", - ev->wd, ev->len > 0 ? ev->name : "", ev->mask); - rescan = true; -@@ -820,7 +857,7 @@ main(int argc, char *argv[]) - * the results of getpw*. - */ - if (setenv("HOME", "/", 1)) { -- printerr(1, "Unable to set $HOME: %s\n", strerror(errno)); -+ printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); - exit(1); - } - -@@ -865,14 +902,16 @@ main(int argc, char *argv[]) - progname = argv[0]; - - initerr(progname, verbosity, fg); --#ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL -- if (verbosity && rpc_verbosity == 0) -- rpc_verbosity = verbosity; -- authgss_set_debug_level(rpc_verbosity); -+#ifdef HAVE_LIBTIRPC_SET_DEBUG -+ /* -+ * Only set the libtirpc debug level if explicitly requested via -r. -+ */ -+ if (rpc_verbosity > 0) -+ libtirpc_set_debug(progname, rpc_verbosity, fg); - #else -- if (rpc_verbosity > 0) -- printerr(0, "Warning: rpcsec_gss library does not " -- "support setting debug level\n"); -+ if (rpc_verbosity > 0) -+ printerr(0, "Warning: libtirpc does not " -+ "support setting debug levels\n"); - #endif - - if (gssd_check_mechs() != 0) -@@ -884,19 +923,19 @@ main(int argc, char *argv[]) - - pipefs_dir = opendir(pipefs_path); - if (!pipefs_dir) { -- printerr(1, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); -+ printerr(0, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); - exit(EXIT_FAILURE); - } - - pipefs_fd = dirfd(pipefs_dir); - if (fchdir(pipefs_fd)) { -- printerr(1, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); -+ printerr(0, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); - exit(EXIT_FAILURE); - } - - inotify_fd = inotify_init1(IN_NONBLOCK); - if (inotify_fd == -1) { -- printerr(1, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); -+ printerr(0, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - -@@ -913,7 +952,7 @@ main(int argc, char *argv[]) - - event_dispatch(); - -- printerr(1, "ERROR: event_dispatch() returned!\n"); -+ printerr(0, "ERROR: event_dispatch() returned!\n"); - return EXIT_FAILURE; - } - -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index c6937c5..565bce3 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - - #ifndef GSSD_PIPEFS_DIR - #define GSSD_PIPEFS_DIR "/var/lib/nfs/rpc_pipefs" -@@ -61,6 +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; -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 11168b2..b19c595 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -69,6 +69,7 @@ - #include - #include - #include -+#include - - #include "gssd.h" - #include "err_util.h" -@@ -150,7 +151,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - unsigned int timeout = context_timeout; - unsigned int buf_size = 0; - -- printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", -+ printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", - 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 + -@@ -189,7 +190,7 @@ do_error_downcall(int k5_fd, uid_t uid, int err) - unsigned int timeout = 0; - int zero = 0; - -- printerr(1, "doing error downcall\n"); -+ printerr(2, "doing error downcall\n"); - - if (WRITE_BYTES(&p, end, uid)) goto out_err; - if (WRITE_BYTES(&p, end, timeout)) goto out_err; -@@ -348,16 +349,9 @@ create_auth_rpc_client(struct clnt_info *clp, - printerr(2, "creating %s client for server %s\n", clp->protocol, - clp->servername); - -- if ((strcmp(clp->protocol, "tcp")) == 0) { -- protocol = IPPROTO_TCP; -- } else if ((strcmp(clp->protocol, "udp")) == 0) { -+ protocol = IPPROTO_TCP; -+ if ((strcmp(clp->protocol, "udp")) == 0) - protocol = IPPROTO_UDP; -- } else { -- printerr(0, "WARNING: unrecognized protocol, '%s', requested " -- "for connection to server %s for user with uid %d\n", -- clp->protocol, clp->servername, uid); -- goto out_fail; -- } - - switch (addr->sa_family) { - case AF_INET: -@@ -443,7 +437,7 @@ change_identity(uid_t uid) - struct passwd *pw; - - /* drop list of supplimentary groups first */ -- if (setgroups(0, NULL) != 0) { -+ if (syscall(SYS_setgroups, 0, 0) != 0) { - printerr(0, "WARNING: unable to drop supplimentary groups!"); - return errno; - } -@@ -460,20 +454,18 @@ change_identity(uid_t uid) - } - } - -- /* -- * Switch the GIDs. Note that we leave the saved-set-gid alone in an -- * attempt to prevent attacks via ptrace() -+ /* Switch the UIDs and GIDs. */ -+ /* For the threaded version we have to set uid,gid per thread instead -+ * of per process. glibc setresuid() when called from a thread, it'll -+ * send a signal to all other threads to synchronize the uid in all -+ * other threads. To bypass this, we have to call syscall() directly. - */ -- if (setresgid(pw->pw_gid, pw->pw_gid, -1) != 0) { -+ if (syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { - printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid); - return errno; - } - -- /* -- * Switch UIDs, but leave saved-set-uid alone to prevent ptrace() by -- * other processes running with this uid. -- */ -- if (setresuid(uid, uid, -1) != 0) { -+ if (syscall(SYS_setresuid, uid, uid, uid) != 0) { - printerr(0, "WARNING: Failed to setuid for user with uid %u\n", - uid); - return errno; -@@ -491,7 +483,7 @@ krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - char **dname; - int err, resp = -1; - -- printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", -+ printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n", - uid, tgtname); - - *chg_err = change_identity(uid); -@@ -538,7 +530,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - int nocache = 0; - int success = 0; - -- printerr(1, "krb5_use_machine_creds: uid %d tgtname %s\n", -+ printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n", - uid, tgtname); - - do { -@@ -555,7 +547,15 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - goto out; - } - for (ccname = credlist; ccname && *ccname; ccname++) { -- gssd_setup_krb5_machine_gss_ccache(*ccname); -+ u_int min_stat; -+ -+ if (gss_krb5_ccache_name(&min_stat, *ccname, NULL) != -+ GSS_S_COMPLETE) { -+ printerr(1, "WARNING: gss_krb5_ccache_name " -+ "with name '%s' failed (%s)\n", -+ *ccname, error_message(min_stat)); -+ continue; -+ } - if ((create_auth_rpc_client(clp, tgtname, rpc_clnt, - &auth, uid, - AUTHTYPE_KRB5, -@@ -564,7 +564,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - success++; - break; - } -- printerr(2, "WARNING: Failed to create machine krb5" -+ printerr(2, "WARNING: Failed to create machine krb5 " - "context with cred cache %s for server %s\n", - *ccname, clp->servername); - } -@@ -572,12 +572,13 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - if (!success) { - if(nocache == 0) { - nocache++; -- printerr(2, "WARNING: Machine cache prematurely" "expired or corrupted trying to" -- "recreate cache for server %s\n", -+ printerr(2, "WARNING: Machine cache prematurely " -+ "expired or corrupted trying to " -+ "recreate cache for server %s\n", - clp->servername); - } else { -- printerr(1, "WARNING: Failed to create machine" -- "krb5 context with any credentials" -+ printerr(1, "ERROR: Failed to create machine " -+ "krb5 context with any credentials " - "cache for server %s\n", - clp->servername); - goto out; -@@ -608,8 +609,6 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - gss_OID mech; - gss_buffer_desc acceptor = {0}; - -- printerr(1, "handling krb5 upcall (%s)\n", clp->relpath); -- - token.length = 0; - token.value = NULL; - memset(&pd, 0, sizeof(struct authgss_private_data)); -@@ -635,41 +634,9 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - * used for this case is not important. - * - */ -- printerr(2, "%s: service is '%s'\n", __func__, -- service ? service : ""); - if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && - service == NULL)) { - -- /* already running as uid 0 */ -- if (uid == 0) -- goto no_fork; -- -- pid = fork(); -- switch(pid) { -- case 0: -- /* Child: fall through to rest of function */ -- childpid = getpid(); -- unsetenv("KRB5CCNAME"); -- printerr(1, "CHILD forked pid %d \n", childpid); -- break; -- case -1: -- /* fork() failed! */ -- printerr(0, "WARNING: unable to fork() to handle" -- "upcall: %s\n", strerror(errno)); -- return; -- default: -- /* Parent: just wait on child to exit and return */ -- do { -- pid = wait(&err); -- } while(pid == -1 && errno != -ECHILD); -- -- if (WIFSIGNALED(err)) -- printerr(0, "WARNING: forked child was killed" -- "with signal %d\n", WTERMSIG(err)); -- return; -- } --no_fork: -- - auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err, - &err, &rpc_clnt); - if (err) -@@ -683,9 +650,7 @@ no_fork: - if (auth == NULL) - goto out_return_error; - } else { -- printerr(1, "WARNING: Failed to create krb5 context " -- "for user with uid %d for server %s\n", -- uid, clp->servername); -+ /* krb5_not_machine_creds logs the error */ - goto out_return_error; - } - } -@@ -716,7 +681,7 @@ no_fork: - * try to use it after this point. - */ - if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { -- printerr(0, "WARNING: Failed to serialize krb5 context for " -+ printerr(1, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for server %s\n", - uid, clp->servername); - goto out_return_error; -@@ -748,17 +713,36 @@ out_return_error: - goto out; - } - -+/* signal to the parent thread that we have read from the file descriptor. -+ * it should allow the parent to proceed to poll on the descriptor for -+ * the next upcall from the kernel. -+ */ -+static inline void -+signal_parent_event_consumed(void) -+{ -+ pthread_mutex_lock(&pmutex); -+ thread_started = true; -+ pthread_cond_signal(&pcond); -+ pthread_mutex_unlock(&pmutex); -+} -+ - void - handle_krb5_upcall(struct clnt_info *clp) - { - uid_t uid; -+ int status; - -- if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { -+ status = read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid); -+ signal_parent_event_consumed(); -+ -+ if (status) { - printerr(0, "WARNING: failed reading uid from krb5 " - "upcall pipe: %s\n", strerror(errno)); - return; - } - -+ printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath); -+ - process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL); - } - -@@ -775,9 +759,9 @@ handle_gssd_upcall(struct clnt_info *clp) - char *service = NULL; - char *enctypes = NULL; - -- printerr(1, "handling gssd upcall (%s)\n", clp->relpath); -- - lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf)); -+ signal_parent_event_consumed(); -+ - if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed reading request\n"); -@@ -785,7 +769,7 @@ handle_gssd_upcall(struct clnt_info *clp) - } - lbuf[lbuflen-1] = 0; - -- printerr(2, "%s: '%s'\n", __func__, lbuf); -+ printerr(2, "\n%s: '%s' (%s)\n", __func__, lbuf, clp->relpath); - - for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) { - if (!strncmp(p, "mech=", strlen("mech="))) -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index ecf17a2..c1e4d2b 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -128,6 +128,7 @@ - - /* 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; - - #ifdef HAVE_SET_ALLOWABLE_ENCTYPES - int limit_to_legacy_enctypes = 0; -@@ -356,7 +357,7 @@ gssd_get_single_krb5_cred(krb5_context context, - */ - now += 300; - if (ple->ccname && ple->endtime > now && !nocache) { -- printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", -+ printerr(3, "INFO: Credentials in CC '%s' are good until %d\n", - ple->ccname, ple->endtime); - code = 0; - goto out; -@@ -383,7 +384,7 @@ gssd_get_single_krb5_cred(krb5_context context, - "tickets. May have problems behind a NAT.\n"); - #ifdef TEST_SHORT_LIFETIME - /* set a short lifetime (for debugging only!) */ -- printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); -+ printerr(1, "WARNING: Using (debug) short machine cred lifetime!\n"); - krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60); - #endif - opts = init_opts; -@@ -451,8 +452,7 @@ gssd_get_single_krb5_cred(krb5_context context, - } - - code = 0; -- printerr(2, "Successfully obtained machine credentials for " -- "principal '%s' stored in ccache '%s'\n", pname, cc_name); -+ printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name); - out: - #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS - if (init_opts) -@@ -468,37 +468,6 @@ gssd_get_single_krb5_cred(krb5_context context, - } - - /* -- * Depending on the version of Kerberos, we either need to use -- * a private function, or simply set the environment variable. -- */ --static void --gssd_set_krb5_ccache_name(char *ccname) --{ --#ifdef USE_GSS_KRB5_CCACHE_NAME -- u_int maj_stat, min_stat; -- -- printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n", -- ccname); -- maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL); -- if (maj_stat != GSS_S_COMPLETE) { -- printerr(0, "WARNING: gss_krb5_ccache_name with " -- "name '%s' failed (%s)\n", -- ccname, error_message(min_stat)); -- } --#else -- /* -- * Set the KRB5CCNAME environment variable to tell the krb5 code -- * which credentials cache to use. (Instead of using the private -- * function above for which there is no generic gssapi -- * equivalent.) -- */ -- printerr(2, "using environment variable to select krb5 ccache %s\n", -- ccname); -- setenv("KRB5CCNAME", ccname, 1); --#endif --} -- --/* - * Given a principal, find a matching ple structure - */ - static struct gssd_k5_kt_princ * -@@ -587,10 +556,12 @@ get_ple_by_princ(krb5_context context, krb5_principal princ) - - /* 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); - } -+ pthread_mutex_unlock(&ple_lock); - - return ple; - } -@@ -797,11 +768,11 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - char **realmnames = NULL; - char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; - char myhostad[NI_MAXHOST+1]; -- int i, j, retval; -+ int i, j, k, retval; - char *default_realm = NULL; - char *realm; - char *k5err = NULL; -- int tried_all = 0, tried_default = 0; -+ int tried_all = 0, tried_default = 0, tried_upper = 0; - krb5_principal princ; - const char *notsetstr = "not set"; - char *adhostoverride; -@@ -835,7 +806,6 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - strcpy(myhostad, myhostname); - for (i = 0; myhostad[i] != 0; ++i) { - if (myhostad[i] == '.') break; -- myhostad[i] = toupper(myhostad[i]); - } - myhostad[i] = '$'; - myhostad[i+1] = 0; -@@ -936,6 +906,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - k5err = gssd_k5_err_msg(context, code); - printerr(3, "%s while getting keytab entry for '%s'\n", - k5err, spn); -+ /* -+ * We tried the active directory machine account -+ * with the hostname part as-is and failed... -+ * convert it to uppercase and try again before -+ * moving on to the svcname -+ */ -+ if (strcmp(svcnames[j],"$") == 0 && !tried_upper) { -+ for (k = 0; myhostad[k] != '$'; ++k) { -+ myhostad[k] = toupper(myhostad[k]); -+ } -+ j--; -+ tried_upper = 1; -+ } - } else { - printerr(3, "Success getting keytab entry for '%s'\n",spn); - retval = 0; -@@ -1080,9 +1063,10 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) - const char *cctype; - struct dirent *d; - int err, i, j; -+ u_int maj_stat, min_stat; - -- printerr(2, "getting credentials for client with uid %u for " -- "server %s\n", uid, servername); -+ printerr(3, "looking for client creds with uid %u for " -+ "server %s in %s\n", uid, servername, dirpattern); - - for (i = 0, j = 0; dirpattern[i] != '\0'; i++) { - switch (dirpattern[i]) { -@@ -1115,22 +1099,16 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) - - printerr(2, "using %s as credentials cache for client with " - "uid %u for server %s\n", buf, uid, servername); -- gssd_set_krb5_ccache_name(buf); -- return 0; --} - --/* -- * Let the gss code know where to find the machine credentials ccache. -- * -- * Returns: -- * void -- */ --void --gssd_setup_krb5_machine_gss_ccache(char *ccname) --{ -- printerr(2, "using %s as credentials cache for machine creds\n", -- ccname); -- gssd_set_krb5_ccache_name(ccname); -+ printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", -+ buf); -+ maj_stat = gss_krb5_ccache_name(&min_stat, buf, NULL); -+ if (maj_stat != GSS_S_COMPLETE) { -+ printerr(0, "ERROR: unable to get user cred cache '%s' " -+ "failed (%s)\n", buf, error_message(min_stat)); -+ return maj_stat; -+ } -+ return 0; - } - - /* -@@ -1398,16 +1376,21 @@ gssd_acquire_krb5_cred(gss_cred_id_t *gss_cred) - int - gssd_acquire_user_cred(gss_cred_id_t *gss_cred) - { -- OM_uint32 min_stat; -+ OM_uint32 maj_stat, min_stat; - int ret; - - ret = gssd_acquire_krb5_cred(gss_cred); - - /* force validation of cred to check for expiry */ - if (ret == 0) { -- if (gss_inquire_cred(&min_stat, *gss_cred, NULL, NULL, -- NULL, NULL) != GSS_S_COMPLETE) -- ret = -1; -+ maj_stat = gss_inquire_cred(&min_stat, *gss_cred, -+ NULL, NULL, NULL, NULL); -+ if (maj_stat != GSS_S_COMPLETE) { -+ if (get_verbosity() > 0) -+ pgsserr("gss_inquire_cred", -+ maj_stat, min_stat, &krb5oid); -+ ret = -1; -+ } - } - - return ret; -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index a319588..e3bbb07 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -27,7 +27,6 @@ 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_setup_krb5_machine_gss_ccache(char *servername); - void gssd_destroy_krb5_machine_creds(void); - int gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -@@ -55,8 +54,6 @@ int limit_krb5_enctypes(struct rpc_gss_sec *sec); - #define k5_free_unparsed_name(ctx, name) free(name) - #define k5_free_default_realm(ctx, realm) free(realm) - #define k5_free_kt_entry(ctx, kte) krb5_kt_free_entry((ctx),(kte)) --#undef USE_GSS_KRB5_CCACHE_NAME --#define USE_GSS_KRB5_CCACHE_NAME 1 - #endif - - #endif /* KRB5_UTIL_H */ -diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c -index f1b4347..0fe7c6d 100644 ---- a/utils/gssd/svcgssd.c -+++ b/utils/gssd/svcgssd.c -@@ -135,6 +135,13 @@ main(int argc, char *argv[]) - if (verbosity && rpc_verbosity == 0) - rpc_verbosity = verbosity; - authgss_set_debug_level(rpc_verbosity); -+#elif HAVE_LIBTIRPC_SET_DEBUG -+ /* -+ * Only set the libtirpc debug level if explicitly requested via -r... -+ * svcgssd is chatty enough as it is. -+ */ -+ if (rpc_verbosity > 0) -+ libtirpc_set_debug(progname, rpc_verbosity, fg); - #else - if (rpc_verbosity > 0) - printerr(0, "Warning: rpcsec_gss library does not " -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 689608a..f4e083a 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -199,6 +199,12 @@ flush_nfsd_idmap_cache(void) - return ret; - } - -+void usage(char *progname) -+{ -+ fprintf(stderr, "Usage: %s [-hfvCS] [-p path] [-c path]\n", -+ basename(progname)); -+} -+ - int - main(int argc, char **argv) - { -@@ -225,16 +231,18 @@ main(int argc, char **argv) - progname = argv[0]; - xlog_open(progname); - --#define GETOPTSTR "vfd:p:U:G:c:CS" -+#define GETOPTSTR "hvfd:p:U:G:c:CS" - opterr=0; /* Turn off error messages */ - while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { - if (opt == 'c') - conf_path = optarg; - if (opt == '?') { - if (strchr(GETOPTSTR, optopt)) -- errx(1, "'-%c' option requires an argument.", optopt); -+ warnx("'-%c' option requires an argument.", optopt); - else -- errx(1, "'-%c' is an invalid argument.", optopt); -+ warnx("'-%c' is an invalid argument.", optopt); -+ usage(progname); -+ exit(1); - } - } - optind = 1; -@@ -276,6 +284,9 @@ main(int argc, char **argv) - case 'S': - clientstart = 0; - break; -+ case 'h': -+ usage(progname); -+ exit(0); - default: - break; - } -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index c809f78..b9200c7 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -10,8 +10,11 @@ - .Sh SYNOPSIS - .\" For a program: program [-abc] file ... - .Nm rpc.idmapd --.Op Fl v -+.Op Fl h - .Op Fl f -+.Op Fl v -+.Op Fl C -+.Op Fl S - .Op Fl p Ar path - .Op Fl c Ar path - .Sh DESCRIPTION -@@ -32,6 +35,8 @@ program. - .Pp - The options are as follows: - .Bl -tag -width Ds_imagedir -+.It Fl h -+Display usage message. - .It Fl v - Increases the verbosity level (can be specified multiple times). - .It Fl f -diff --git a/utils/mount/network.c b/utils/mount/network.c -index b5ed850..0d12613 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -92,6 +92,7 @@ static const char *nfs_version_opttbl[] = { - "v4", - "vers", - "nfsvers", -+ "minorversion", - NULL, - }; - -@@ -793,6 +794,8 @@ int start_statd(void) - if (stat(START_STATD, &stb) == 0) { - if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) { - int cnt = STATD_TIMEOUT * 10; -+ int status = 0; -+ char * const envp[1] = { NULL }; - const struct timespec ts = { - .tv_sec = 0, - .tv_nsec = 100000000, -@@ -800,14 +803,19 @@ int start_statd(void) - pid_t pid = fork(); - switch (pid) { - case 0: /* child */ -- execl(START_STATD, START_STATD, NULL); -+ setgid(0); -+ setuid(0); -+ execle(START_STATD, START_STATD, NULL, envp); - exit(1); - case -1: /* error */ - nfs_error(_("%s: fork failed: %s"), - progname, strerror(errno)); - break; - default: /* parent */ -- waitpid(pid, NULL,0); -+ if (waitpid(pid, &status,0) == pid && -+ status == 0) -+ /* assume it worked */ -+ return 1; - break; - } - while (1) { -@@ -1272,7 +1280,11 @@ nfs_nfs_version(struct mount_options *options, struct nfs_version *version) - if (!(version->major = strtol(version_val, &cptr, 10))) - goto ret_error; - -- if (version->major < 4) -+ if (strcmp(nfs_version_opttbl[i], "minorversion") == 0) { -+ version->v_mode = V_SPECIFIC; -+ version->minor = version->major; -+ version->major = 4; -+ } else if (version->major < 4) - version->v_mode = V_SPECIFIC; - - if (*cptr == '.') { -@@ -1626,7 +1638,10 @@ int nfs_options2pmap(struct mount_options *options, - return 0; - if (!nfs_nfs_version(options, &version)) - return 0; -- nfs_pmap->pm_vers = version.major; -+ if (version.v_mode == V_DEFAULT) -+ nfs_pmap->pm_vers = 0; -+ else -+ nfs_pmap->pm_vers = version.major; - if (!nfs_nfs_protocol(options, &nfs_pmap->pm_prot)) - return 0; - if (!nfs_nfs_port(options, &nfs_pmap->pm_port)) -diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c -index d64b83d..0d3bcb9 100644 ---- a/utils/mount/parse_dev.c -+++ b/utils/mount/parse_dev.c -@@ -118,7 +118,8 @@ static int nfs_parse_simple_hostname(const char *dev, - if (pathname) { - *pathname = strndup(colon, path_len); - if (*pathname == NULL) { -- free(*hostname); -+ if (hostname) -+ free(*hostname); - return nfs_pdn_nomem_err(); - } - } -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index c8f5a6d..d60b484 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -383,13 +383,26 @@ static int nfs_validate_options(struct nfsmount_info *mi) - if (!nfs_nfs_proto_family(mi->options, &family)) - return 0; - -- hint.ai_family = (int)family; -- error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); -- if (error != 0) { -- nfs_error(_("%s: Failed to resolve server %s: %s"), -- progname, mi->hostname, gai_strerror(error)); -- mi->address = NULL; -- return 0; -+ /* -+ * A remount is not going to be able to change the server's address, -+ * nor should we try to resolve another address for the server as we -+ * may end up with a different address. -+ */ -+ if (mi->flags & MS_REMOUNT) { -+ po_remove_all(mi->options, "addr"); -+ } else { -+ hint.ai_family = (int)family; -+ error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); -+ if (error != 0) { -+ nfs_error(_("%s: Failed to resolve server %s: %s"), -+ progname, mi->hostname, gai_strerror(error)); -+ mi->address = NULL; -+ return 0; -+ } -+ -+ if (!nfs_append_addr_option(mi->address->ai_addr, -+ mi->address->ai_addrlen, mi->options)) -+ return 0; - } - - if (!nfs_set_version(mi)) -@@ -398,10 +411,6 @@ static int nfs_validate_options(struct nfsmount_info *mi) - if (!nfs_append_sloppy_option(mi->options)) - return 0; - -- if (!nfs_append_addr_option(mi->address->ai_addr, -- mi->address->ai_addrlen, mi->options)) -- return 0; -- - return 1; - } - -@@ -841,6 +850,9 @@ check_result: - case EPROTONOSUPPORT: - /* A clear indication that the server or our - * client does not support NFS version 4 and minor */ -+ case EINVAL: -+ /* A less clear indication that our client -+ * does not support NFSv4 minor version. */ - if (mi->version.v_mode == V_GENERAL && - mi->version.minor == 0) - return result; -@@ -957,6 +969,15 @@ static int nfsmount_fg(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -+ if (errno == EBUSY) -+ /* The only cause of EBUSY is if exactly the desired -+ * filesystem is already mounted. That can arguably -+ * be seen as success. "mount -a" tries to optimise -+ * out this case but sometimes fails. Help it out -+ * by pretending everything is rosy -+ */ -+ return EX_SUCCESS; -+ - if (nfs_is_permanent_error(errno)) - break; - -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index 330cab5..894a7a5 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -85,7 +85,7 @@ auth_reload() - { - struct stat stb; - static ino_t last_inode; -- static int last_fd; -+ static int last_fd = -1; - static unsigned int counter; - int fd; - -@@ -93,11 +93,22 @@ auth_reload() - xlog(L_FATAL, "couldn't open %s", _PATH_ETAB); - } else if (fstat(fd, &stb) < 0) { - xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB); -- } else if (stb.st_ino == last_inode) { -+ close(fd); -+ } else if (last_fd != -1 && stb.st_ino == last_inode) { -+ /* We opened the etab file before, and its inode -+ * number hasn't changed since then. -+ */ - close(fd); - return counter; - } else { -- close(last_fd); -+ /* Need to process entries from the etab file. Close -+ * the file descriptor from the previous open (last_fd), -+ * and keep the current file descriptor open to prevent -+ * the file system reusing the current inode number -+ * (last_inode). -+ */ -+ if (last_fd != -1) -+ close(last_fd); - last_fd = fd; - last_inode = stb.st_ino; - } -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 7847446..ec86a22 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -31,6 +31,7 @@ - #include "mountd.h" - #include "fsloc.h" - #include "pseudoflavors.h" -+#include "xcommon.h" - - #ifdef USE_BLKID - #include "blkid/blkid.h" -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 9fe0f40..b584afc 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -794,9 +794,10 @@ main(int argc, char **argv) - } - - /* No more arguments allowed. */ -- if (optind != argc || !version_any()) -+ if (optind != argc || !version_any()) { -+ fprintf(stderr, "%s: No protocol versions specified!\n", progname); - usage(progname, 1); -- -+ } - if (chdir(state_dir)) { - fprintf(stderr, "%s: chdir(%s) failed: %s\n", - progname, state_dir, strerror(errno)); -@@ -910,7 +911,8 @@ usage(const char *prog, int n) - " [-o num|--descriptors num] [-f exports-file|--exports-file=file]\n" - " [-p|--port port] [-V version|--nfs-version version]\n" - " [-N version|--no-nfs-version version] [-n|--no-tcp]\n" --" [-H ha-callout-prog] [-s|--state-directory-path path]\n" --" [-g|--manage-gids] [-t num|--num-threads=num] [-u|--no-udp]\n", prog); -+" [-H ha-callout prog] [-r | --reverse-lookup]\n" -+" [-s|--state-directory-path path] [-g|--manage-gids]\n" -+" [-t num|--num-threads=num] [-u|--no-udp]\n", prog); - exit(n); - } -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index 7c5bfbe..66e3bba 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -115,10 +115,7 @@ must be invoked with the option - .B \-n " or " \-\-no-tcp - Don't advertise TCP for mount. - .TP --.B \-P --Ignored (compatibility with unfsd??). --.TP --.B \-p num " or " \-\-port num -+.B \-p num " or " \-P num " or " \-\-port num - Specifies the port number used for RPC listener sockets. - If this option is not specified, - .B rpc.mountd -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index a2b11d8..dcb430a 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -168,22 +168,22 @@ nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port) - continue; - } - -- xlog(D_GENERAL, "Creating %s %s socket.", family, proto); -- - /* open socket and prepare to hand it off to kernel */ - sockfd = socket(addr->ai_family, addr->ai_socktype, - addr->ai_protocol); - if (sockfd < 0) { -- if (errno == EAFNOSUPPORT) -- xlog(L_NOTICE, "address family %s not " -- "supported by protocol %s", -- family, proto); -- else -+ if (errno != EAFNOSUPPORT) { - xlog(L_ERROR, "unable to create %s %s socket: " - "errno %d (%m)", family, proto, errno); -- rc = errno; -- goto error; -+ rc = errno; -+ goto error; -+ } -+ addr = addr->ai_next; -+ continue; - } -+ -+ xlog(D_GENERAL, "Created %s %s socket.", family, proto); -+ - #ifdef IPV6_SUPPORTED - if (addr->ai_family == AF_INET6 && - setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) { -@@ -282,7 +282,7 @@ nfssvc_set_rdmaport(const char *port) - int fd; - - if (sv) -- nport = sv->s_port; -+ nport = ntohs(sv->s_port); - else { - char *ep; - nport = strtol(port, &ep, 10); -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 507193b..2abefe9 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -80,8 +80,9 @@ static int keyring_clear(const char *keyring) - - key = find_key_by_type_and_desc("keyring", keyring, 0); - if (key == -1) { -- xlog_err("'%s' keyring was not found.", keyring); -- return EXIT_FAILURE; -+ if (verbose) -+ xlog_warn("'%s' keyring was not found.", keyring); -+ return EXIT_SUCCESS; - } - - if (keyctl_clear(key) < 0) { -@@ -89,10 +90,9 @@ static int keyring_clear(const char *keyring) - (unsigned int)key); - return EXIT_FAILURE; - } -- -+ - if (verbose) - xlog_warn("'%s' cleared", keyring); -- - return EXIT_SUCCESS; - } - -@@ -404,6 +404,11 @@ int main(int argc, char **argv) - } - } - -+ if (geteuid() != 0) { -+ xlog_err("Must be run as root."); -+ return EXIT_FAILURE; -+ } -+ - if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF))) { - xlog_errno(rc, "Unable to create name to user id mappings."); - return EXIT_FAILURE; -@@ -423,9 +428,9 @@ int main(int argc, char **argv) - return keyring_clear(DEFAULT_KEYRING); - } - -- xlog_stderr(0); -+ xlog_stderr(verbose); - if ((argc - optind) != 2) { -- xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn("Bad arg count. Check /etc/request-key.conf"); - xlog_warn(usage, progname); - return EXIT_FAILURE; - } -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index 9f481db..8376347 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -31,8 +31,8 @@ enum { - SRVPROC3_SZ = 22, - CLTPROC3_SZ = 22, - SRVPROC4_SZ = 2, -- CLTPROC4_SZ = 49, -- SRVPROC4OPS_SZ = 59, -+ CLTPROC4_SZ = 59, -+ SRVPROC4OPS_SZ = 71, - }; - - static unsigned int srvproc2info[SRVPROC2_SZ+2], -@@ -127,19 +127,30 @@ static const char * nfscltproc4name[CLTPROC4_SZ] = { - "remove", "rename", "link", "symlink", "create", "pathconf", - "statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl", - "setacl", "fs_locations", -- "rel_lkowner", "secinfo", -+ "rel_lkowner", "secinfo", "fsid_present", - /* nfsv4.1 client ops */ - "exchange_id", -- "create_ses", -- "destroy_ses", -+ "create_session", -+ "destroy_session", - "sequence", -- "get_lease_t", -+ "get_lease_time", - "reclaim_comp", - "layoutget", - "getdevinfo", - "layoutcommit", - "layoutreturn", -- "getdevlist", -+ "secinfo_no", -+ "test_stateid", -+ "free_stateid", -+ "getdevicelist", -+ "bind_conn_to_ses", -+ "destroy_clientid", -+ /* nfsv4.2 client ops */ -+ "seek", -+ "allocate", -+ "deallocate", -+ "layoutstats", -+ "clone", - }; - - static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = { -@@ -170,6 +181,19 @@ static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = { - "want_deleg", - "destroy_clid", - "reclaim_comp", -+ /* nfsv4.2 server ops */ -+ "allocate", -+ "copy", -+ "copy_notify", -+ "deallocate", -+ "ioadvise", -+ "layouterror", -+ "layoutstats", -+ "offloadcancel", -+ "offloadstatus", -+ "readplus", -+ "seek", -+ "write_same", - }; - - #define LABEL_srvnet "Server packet stats:\n" -@@ -823,13 +847,13 @@ print_callstats(const char *hdr, const char **names, - total += info[i]; - if (!total) - total = 1; -- for (i = 0; i < nr; i += 6) { -- for (j = 0; j < 6 && i + j < nr; j++) -- printf("%-13s", names[i+j]); -+ for (i = 0; i < nr; i += 5) { -+ for (j = 0; j < 5 && i + j < nr; j++) -+ printf("%-17s", names[i+j]); - printf("\n"); -- for (j = 0; j < 6 && i + j < nr; j++) { -+ for (j = 0; j < 5 && i + j < nr; j++) { - pct = ((unsigned long long) info[i+j]*100)/total; -- printf("%-8u%3llu%% ", info[i+j], pct); -+ printf("%-8u%3llu%% ", info[i+j], pct); - } - printf("\n"); - } -diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c -index c61087c..8cccdb8 100644 ---- a/utils/statd/hostname.c -+++ b/utils/statd/hostname.c -@@ -180,9 +180,6 @@ get_nameinfo(const struct sockaddr *sap, - * Incoming hostnames are looked up to determine the canonical hostname, - * and incoming presentation addresses are converted to canonical - * hostnames. -- * -- * We won't monitor peers that don't have a reverse map. The canonical -- * name gives us a key for our monitor list. - */ - __attribute__((__malloc__)) - char * -@@ -207,7 +204,7 @@ statd_canonical_name(const char *hostname) - result = get_nameinfo(ai->ai_addr, ai->ai_addrlen, - buf, (socklen_t)sizeof(buf)); - freeaddrinfo(ai); -- if (!result) -+ if (!result || buf[0] == '\0') - /* OK to use presentation address, - * if no reverse map exists */ - return strdup(hostname); -diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c -index 286a5e2..368bd80 100644 ---- a/utils/statd/monitor.c -+++ b/utils/statd/monitor.c -@@ -72,6 +72,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - }; - char *dnsname = NULL; -+ int existing = 0; - - xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name); - -@@ -148,17 +149,26 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - if (statd_matchhostname(NL_MY_NAME(clnt), my_name) && - NL_MY_PROC(clnt) == id->my_proc && - NL_MY_PROG(clnt) == id->my_prog && -- NL_MY_VERS(clnt) == id->my_vers && -- memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) { -- /* Hey! We already know you guys! */ -- xlog(D_GENERAL, -- "Duplicate SM_MON request for %s " -- "from procedure on %s", -- mon_name, my_name); -+ NL_MY_VERS(clnt) == id->my_vers) { -+ if (memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE)) { -+ xlog(D_GENERAL, -+ "Received SM_MON request with new " -+ "cookie for %s from procedure on %s", -+ mon_name, my_name); -+ -+ existing = 1; -+ break; -+ } else { -+ /* Hey! We already know you guys! */ -+ xlog(D_GENERAL, -+ "Duplicate SM_MON request for %s " -+ "from procedure on %s", -+ mon_name, my_name); - -- /* But we'll let you pass anyway. */ -- free(dnsname); -- goto success; -+ /* But we'll let you pass anyway. */ -+ free(dnsname); -+ goto success; -+ } - } - clnt = NL_NEXT(clnt); - } -@@ -167,7 +177,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - * We're committed...ignoring errors. Let's hope that a malloc() - * doesn't fail. (I should probably fix this assumption.) - */ -- if (!(clnt = nlist_new(my_name, mon_name, 0))) { -+ if (!existing && !(clnt = nlist_new(my_name, mon_name, 0))) { - free(dnsname); - xlog_warn("out of memory"); - goto failure; -@@ -180,8 +190,11 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - clnt->dns_name = dnsname; - - /* -- * Now, Create file on stable storage for host. -+ * Now, Create file on stable storage for host, first deleting any -+ * existing records on file. - */ -+ nsm_delete_monitored_host(dnsname, mon_name, my_name); -+ - if (!nsm_insert_monitored_host(dnsname, - (struct sockaddr *)(char *)&my_addr, argp)) { - nlist_free(NULL, clnt); -@@ -190,7 +203,8 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - - /* PRC: do the HA callout: */ - ha_callout("add-client", mon_name, my_name, -1); -- nlist_insert(&rtnl, clnt); -+ if (!existing) -+ nlist_insert(&rtnl, clnt); - xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name); - success: - result.res_stat = STAT_SUCC; -diff --git a/utils/statd/rmtcall.c b/utils/statd/rmtcall.c -index 45c84f9..c4f6364 100644 ---- a/utils/statd/rmtcall.c -+++ b/utils/statd/rmtcall.c -@@ -113,7 +113,6 @@ statd_get_socket(void) - if (sockfd < 0) - return -1; - -- FD_SET(sockfd, &SVC_FDSET); - return sockfd; - } - -diff --git a/utils/statd/start-statd b/utils/statd/start-statd -index 14369e5..19e6eb2 100755 ---- a/utils/statd/start-statd -+++ b/utils/statd/start-statd -@@ -6,11 +6,19 @@ - # site. - PATH="/sbin:/usr/sbin:/bin:/usr/bin" - -+if [ -s /var/run/rpc.statd.pid ] && -+ [ 1`cat /var/run/rpc.statd.pid` -gt 1 ] && -+ kill -0 `cat /var/run/rpc.statd.pid` > /dev/null 2>&1 -+then -+ # statd already running - must have been slow to respond. -+ exit 0 -+fi - # First try systemd if it's installed. - if [ -d /run/systemd/system ]; then - # Quit only if the call worked. - systemctl start rpc-statd.service && exit - fi - -+cd / - # Fall back to launching it ourselves. - exec rpc.statd --no-notify -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 2b7a167..e5b4c98 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -247,6 +247,7 @@ int main (int argc, char **argv) - int port = 0, out_port = 0; - int nlm_udp = 0, nlm_tcp = 0; - struct rlimit rlim; -+ int notify_sockfd; - - /* Default: daemon mode, no other options */ - run_mode = 0; -@@ -437,7 +438,7 @@ int main (int argc, char **argv) - } - - /* Make sure we have a privilege port for calling into the kernel */ -- if (statd_get_socket() < 0) -+ if ((notify_sockfd = statd_get_socket()) < 0) - exit(1); - - /* If sm-notify didn't take all the state files, load -@@ -484,7 +485,7 @@ int main (int argc, char **argv) - * Handle incoming requests: SM_NOTIFY socket requests, as - * well as callbacks from lockd. - */ -- my_svc_run(); /* I rolled my own, Olaf made it better... */ -+ my_svc_run(notify_sockfd); /* I rolled my own, Olaf made it better... */ - - /* Only get here when simulating a crash so we should probably - * start sm-notify running again. As we have already dropped -diff --git a/utils/statd/statd.h b/utils/statd/statd.h -index a1d8035..231ac7e 100644 ---- a/utils/statd/statd.h -+++ b/utils/statd/statd.h -@@ -28,7 +28,7 @@ extern _Bool statd_present_address(const struct sockaddr *sap, char *buf, - __attribute__((__malloc__)) - extern char * statd_canonical_name(const char *hostname); - --extern void my_svc_run(void); -+extern void my_svc_run(int); - extern void notify_hosts(void); - extern void shuffle_dirs(void); - extern int statd_get_socket(void); -diff --git a/utils/statd/svc_run.c b/utils/statd/svc_run.c -index d98ecee..28c1ad6 100644 ---- a/utils/statd/svc_run.c -+++ b/utils/statd/svc_run.c -@@ -78,7 +78,7 @@ my_svc_exit(void) - * The heart of the server. A crib from libc for the most part... - */ - void --my_svc_run(void) -+my_svc_run(int sockfd) - { - FD_SET_TYPE readfds; - int selret; -@@ -96,6 +96,8 @@ my_svc_run(void) - } - - readfds = SVC_FDSET; -+ /* Set notify sockfd for waiting for reply */ -+ FD_SET(sockfd, &readfds); - if (notify) { - struct timeval tv; - -@@ -125,8 +127,10 @@ my_svc_run(void) - - default: - selret -= process_reply(&readfds); -- if (selret) -+ if (selret) { -+ FD_CLR(sockfd, &readfds); - svc_getreqset(&readfds); -+ } - } - } - } diff --git a/nfs-utils-1.3.4-rc6.patch b/nfs-utils-1.3.4-rc6.patch deleted file mode 100644 index 7d1b29d..0000000 --- a/nfs-utils-1.3.4-rc6.patch +++ /dev/null @@ -1,2647 +0,0 @@ -diff --git a/aclocal/kerberos5.m4 b/aclocal/kerberos5.m4 -index 0bf35d3..8a0f3e4 100644 ---- a/aclocal/kerberos5.m4 -+++ b/aclocal/kerberos5.m4 -@@ -43,15 +43,6 @@ AC_DEFUN([AC_KERBEROS_V5],[ - -f $dir/lib/libgssapi_krb5.so \) ; then - AC_DEFINE(HAVE_KRB5, 1, [Define this if you have MIT Kerberos libraries]) - KRBDIR="$dir" -- dnl If we are using MIT K5 1.3.1 and before, we *MUST* use the -- dnl private function (gss_krb5_ccache_name) to get correct -- dnl behavior of changing the ccache used by gssapi. -- dnl Starting in 1.3.2, we *DO NOT* want to use -- dnl gss_krb5_ccache_name, instead we want to set KRB5CCNAME -- dnl to get gssapi to use a different ccache -- if test $K5VERS -le 131; then -- AC_DEFINE(USE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the private function, gss_krb5_cache_name, must be used to tell the Kerberos library which credentials cache to use. Otherwise, this is done by setting the KRB5CCNAME environment variable]) -- fi - gssapi_lib=gssapi_krb5 - break - dnl The following ugly hack brought on by the split installation -@@ -92,8 +83,6 @@ AC_DEFUN([AC_KERBEROS_V5],[ - AC_DEFINE(HAVE_LUCID_CONTEXT_SUPPORT, 1, [Define this if the Kerberos GSS library supports gss_krb5_export_lucid_sec_context]), ,$KRBLIBS) - AC_CHECK_LIB($gssapi_lib, gss_krb5_set_allowable_enctypes, - AC_DEFINE(HAVE_SET_ALLOWABLE_ENCTYPES, 1, [Define this if the Kerberos GSS library supports gss_krb5_set_allowable_enctypes]), ,$KRBLIBS) -- AC_CHECK_LIB($gssapi_lib, gss_krb5_ccache_name, -- AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the Kerberos GSS library supports gss_krb5_ccache_name]), ,$KRBLIBS) - AC_CHECK_LIB($gssapi_lib, gss_krb5_free_lucid_sec_context, - AC_DEFINE(HAVE_GSS_KRB5_FREE_LUCID_SEC_CONTEXT, 1, [Define this if the Kerberos GSS library supports gss_krb5_free_lucid_sec_context]), ,$KRBLIBS) - -diff --git a/aclocal/libpthread.m4 b/aclocal/libpthread.m4 -new file mode 100644 -index 0000000..e87d2a0 ---- /dev/null -+++ b/aclocal/libpthread.m4 -@@ -0,0 +1,13 @@ -+dnl Checks for pthreads library and headers -+dnl -+AC_DEFUN([AC_LIBPTHREAD], [ -+ -+ dnl Check for library, but do not add -lpthreads to LIBS -+ AC_CHECK_LIB([pthread], [pthread_create], [LIBPTHREAD=-lpthread], -+ [AC_MSG_ERROR([libpthread not found.])]) -+ AC_SUBST(LIBPTHREAD) -+ -+ AC_CHECK_HEADERS([pthread.h], , -+ [AC_MSG_ERROR([libpthread headers not found.])]) -+ -+])dnl -diff --git a/aclocal/librpcsecgss.m4 b/aclocal/librpcsecgss.m4 -deleted file mode 100644 -index e833141..0000000 ---- a/aclocal/librpcsecgss.m4 -+++ /dev/null -@@ -1,21 +0,0 @@ --dnl Checks for rpcsecgss library and headers --dnl KRB5LIBS must be set before this function is invoked. --dnl --AC_DEFUN([AC_LIBRPCSECGSS], [ -- -- dnl libtirpc provides an rpcsecgss API -- if test "$enable_tirpc" = no; then -- -- dnl Check for library, but do not add -lrpcsecgss to LIBS -- AC_CHECK_LIB([rpcsecgss], [authgss_create_default], [librpcsecgss=1], -- [AC_MSG_ERROR([librpcsecgss not found.])]) -- -- AC_CHECK_LIB([rpcsecgss], [authgss_set_debug_level], -- [AC_DEFINE([HAVE_AUTHGSS_SET_DEBUG_LEVEL], 1, -- [Define to 1 if you have the `authgss_set_debug_level' function.])]) -- -- AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1, -- [Define to 1 if your rpcsec library provides authgss_free_private_data,]) -- fi -- --])dnl -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index b7de636..27368ff 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -20,6 +20,12 @@ AC_DEFUN([AC_LIBTIRPC], [ - [Define to 1 if your rpcsec library provides authgss_free_private_data])],, - [${LIBS}])]) - -+ AS_IF([test -n "${LIBTIRPC}"], -+ [AC_CHECK_LIB([tirpc], [libtirpc_set_debug], -+ [AC_DEFINE([HAVE_LIBTIRPC_SET_DEBUG], [1], -+ [Define to 1 if your tirpc library provides libtirpc_set_debug])],, -+ [${LIBS}])]) -+ - AC_SUBST([AM_CPPFLAGS]) - AC_SUBST(LIBTIRPC) - -diff --git a/configure.ac b/configure.ac -index 25d2ba4..1daf5b8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -382,8 +382,8 @@ if test "$enable_gss" = yes; then - dnl Check for Kerberos V5 - AC_KERBEROS_V5 - -- dnl Invoked after AC_KERBEROS_V5; AC_LIBRPCSECGSS needs to have KRBLIBS set -- AC_LIBRPCSECGSS -+ dnl Check for pthreads -+ AC_LIBPTHREAD - - dnl librpcsecgss already has a dependency on libgssapi, - dnl but we need to make sure we get the right version -diff --git a/support/export/client.c b/support/export/client.c -index 95156f0..2346f99 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -639,7 +639,7 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - const char *netgroup = clp->m_hostname + 1; - struct addrinfo *tmp = NULL; - struct hostent *hp; -- char *dot, *hname; -+ char *dot, *hname, *ip; - int i, match; - - match = 0; -@@ -686,6 +686,18 @@ check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - } - } - -+ /* check whether the IP itself is in the netgroup */ -+ ip = calloc(INET6_ADDRSTRLEN, 1); -+ if (inet_ntop(ai->ai_family, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, INET6_ADDRSTRLEN) == ip) { -+ if (innetgr(netgroup, ip, NULL, NULL)) { -+ free(hname); -+ hname = ip; -+ match = 1; -+ goto out; -+ } -+ } -+ free(ip); -+ - /* Okay, strip off the domain (if we have one) */ - dot = strchr(hname, '.'); - if (dot == NULL) -diff --git a/support/export/hostname.c b/support/export/hostname.c -index 169baa5..5c4c824 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -69,7 +69,7 @@ host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) - - memset(buf, 0, buflen); - -- if (sin->sin_family != AF_INET) -+ if (sin->sin_family != AF_INET) { - (void)strncpy(buf, "bad family", buflen - 1); - return buf; - } -@@ -134,12 +134,14 @@ host_pton(const char *paddr) - break; - } - return ai; -+ case EAI_NONAME: -+ break; - case EAI_SYSTEM: -- xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", -+ xlog(L_WARNING, "%s: failed to convert %s: (%d) %m", - __func__, paddr, errno); - break; - default: -- xlog(D_GENERAL, "%s: failed to convert %s: %s", -+ xlog(L_WARNING, "%s: failed to convert %s: %s", - __func__, paddr, gai_strerror(error)); - break; - } -@@ -228,7 +230,7 @@ host_canonname(const struct sockaddr *sap) - default: - (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), - NULL, 0, NI_NUMERICHOST); -- xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ xlog(D_PARSE, "%s: failed to resolve %s: %s", - __func__, buf, gai_strerror(error)); - return NULL; - } -diff --git a/support/include/ha-callout.h b/support/include/ha-callout.h -index 1164336..a454bdb 100644 ---- a/support/include/ha-callout.h -+++ b/support/include/ha-callout.h -@@ -47,7 +47,7 @@ ha_callout(char *event, char *arg1, char *arg2, int arg3) - arg3 < 0 ? NULL : buf, - NULL); - perror("execl"); -- exit(2); -+ _exit(2); - case -1: perror("fork"); - break; - default: pid = waitpid(pid, &ret, 0); -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index c9a13cb..ddd71ac 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -176,6 +176,9 @@ size_t strlcpy(char *, const char *, size_t); - ssize_t atomicio(ssize_t (*f) (int, void*, size_t), - int, void *, size_t); - -+#ifdef HAVE_LIBTIRPC_SET_DEBUG -+void libtirpc_set_debug(char *name, int level, int use_stderr); -+#endif - - #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) - -diff --git a/support/include/nsm.h b/support/include/nsm.h -index fb4d823..080d176 100644 ---- a/support/include/nsm.h -+++ b/support/include/nsm.h -@@ -59,7 +59,8 @@ extern unsigned int - extern _Bool nsm_insert_monitored_host(const char *hostname, - const struct sockaddr *sap, const struct mon *m); - extern void nsm_delete_monitored_host(const char *hostname, -- const char *mon_name, const char *my_name); -+ const char *mon_name, const char *my_name, -+ const int chatty); - extern void nsm_delete_notified_host(const char *hostname, - const char *mon_name, const char *my_name); - extern size_t nsm_priv_to_hex(const char *priv, char *buf, -diff --git a/support/include/xcommon.h b/support/include/xcommon.h -index d1a4b18..23c9a13 100644 ---- a/support/include/xcommon.h -+++ b/support/include/xcommon.h -@@ -17,6 +17,12 @@ - #include - #include - -+#ifdef MAJOR_IN_MKDEV -+#include -+#elif defined(MAJOR_IN_SYSMACROS) -+#include -+#endif -+ - #define streq(s, t) (strcmp ((s), (t)) == 0) - - /* Functions in sundries.c that are used in mount.c and umount.c */ -diff --git a/support/nfs/closeall.c b/support/nfs/closeall.c -index 38fb162..a69bf35 100644 ---- a/support/nfs/closeall.c -+++ b/support/nfs/closeall.c -@@ -31,6 +31,7 @@ closeall(int min) - } else { - int fd = sysconf(_SC_OPEN_MAX); - while (--fd >= min) -- (void) close(fd); -+ if(fd >= 0) -+ (void) close(fd); - } - } -diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c -index 3391eff..343e80b 100644 ---- a/support/nfs/mydaemon.c -+++ b/support/nfs/mydaemon.c -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - #include - - #include "nfslib.h" -@@ -122,6 +123,7 @@ daemon_init(bool fg) - dup2(tempfd, 0); - dup2(tempfd, 1); - dup2(tempfd, 2); -+ closelog(); - dup2(pipefds[1], 3); - pipefds[1] = 3; - closeall(4); -diff --git a/support/nfs/nfsexport.c b/support/nfs/nfsexport.c -index afd7c90..4b13265 100644 ---- a/support/nfs/nfsexport.c -+++ b/support/nfs/nfsexport.c -@@ -19,6 +19,7 @@ - - #include "nfslib.h" - #include "misc.h" -+#include "xcommon.h" - - /* if /proc/net/rpc/... exists, then - * write to it, as that interface is more stable. -diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c -index 2900d18..bdf6d2f 100644 ---- a/support/nfs/rpc_socket.c -+++ b/support/nfs/rpc_socket.c -@@ -185,7 +185,7 @@ static int nfs_connect_nb(const int fd, const struct sockaddr *sap, - * use it later. - */ - ret = connect(fd, sap, salen); -- if (ret < 0 && errno != EINPROGRESS) { -+ if (ret < 0 && errno != EINPROGRESS && errno != EINTR) { - ret = -1; - goto done; - } -@@ -197,10 +197,16 @@ static int nfs_connect_nb(const int fd, const struct sockaddr *sap, - FD_ZERO(&rset); - FD_SET(fd, &rset); - -- ret = select(fd + 1, NULL, &rset, NULL, timeout); -- if (ret <= 0) { -- if (ret == 0) -- errno = ETIMEDOUT; -+ while ((ret = select(fd + 1, NULL, &rset, NULL, timeout)) < 0) { -+ if (errno != EINTR) { -+ ret = -1; -+ goto done; -+ } else { -+ continue; -+ } -+ } -+ if (ret == 0) { -+ errno = ETIMEDOUT; - ret = -1; - goto done; - } -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index 5cb5ff6..ef7ff05 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -133,7 +133,7 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - hint.ai_family = AF_INET6; - #endif /* IPV6_SUPPORTED */ - else { -- xlog(D_GENERAL, "Unrecognized bind address family: %s", -+ xlog(L_ERROR, "Unrecognized bind address family: %s", - nconf->nc_protofmly); - return NULL; - } -@@ -143,7 +143,7 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - else if (strcmp(nconf->nc_proto, NC_TCP) == 0) - hint.ai_protocol = (int)IPPROTO_TCP; - else { -- xlog(D_GENERAL, "Unrecognized bind address protocol: %s", -+ xlog(L_ERROR, "Unrecognized bind address protocol: %s", - nconf->nc_proto); - return NULL; - } -@@ -275,7 +275,7 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0); - freeaddrinfo(ai); - if (xprt == NULL) { -- xlog(D_GENERAL, "Failed to create listener xprt " -+ xlog(L_ERROR, "Failed to create listener xprt " - "(%s, %u, %s)", name, version, nconf->nc_netid); - return 0; - } -@@ -286,10 +286,12 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - return 0; - } - -+ rpc_createerr.cf_stat = rpc_createerr.cf_error.re_errno = 0; - if (!svc_reg(xprt, program, version, dispatch, nconf)) { - /* svc_reg(3) destroys @xprt in this case */ -- xlog(D_GENERAL, "Failed to register (%s, %u, %s)", -- name, version, nconf->nc_netid); -+ xlog(L_ERROR, "Failed to register (%s, %u, %s): %s", -+ name, version, nconf->nc_netid, -+ clnt_spcreateerror("svc_reg() err")); - return 0; - } - -diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c -index 99321e7..1fa0d15 100644 ---- a/support/nfs/svc_socket.c -+++ b/support/nfs/svc_socket.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include "xlog.h" - - #include "config.h" - -@@ -99,9 +100,9 @@ svcsock_nonblock(int sock) - * connection. - */ - if ((flags = fcntl(sock, F_GETFL)) < 0) -- perror(_("svc_socket: can't get socket flags")); -+ xlog(L_ERROR, "svc_socket: can't get socket flags: %m"); - else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -- perror(_("svc_socket: can't set socket flags")); -+ xlog(L_ERROR, "svc_socket: can't set socket flags: %m"); - else - return sock; - -@@ -119,7 +120,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - - if ((sock = __socket (AF_INET, type, protocol)) < 0) - { -- perror (_("svc_socket: socket creation problem")); -+ xlog(L_ERROR, "svc_socket: socket creation problem: %m"); - return sock; - } - -@@ -130,7 +131,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - sizeof (ret)); - if (ret < 0) - { -- perror (_("svc_socket: socket reuse problem")); -+ xlog(L_ERROR, "svc_socket: socket reuse problem: %m"); - return ret; - } - } -@@ -141,7 +142,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - - if (bind(sock, (struct sockaddr *) &addr, len) < 0) - { -- perror (_("svc_socket: bind problem")); -+ xlog(L_ERROR, "svc_socket: bind problem: %m"); - (void) __close(sock); - sock = -1; - } -diff --git a/support/nsm/file.c b/support/nsm/file.c -index 4711c2c..aafa755 100644 ---- a/support/nsm/file.c -+++ b/support/nsm/file.c -@@ -536,7 +536,8 @@ nsm_get_state(_Bool update) - state++; - - update: -- (void)close(fd); -+ if(fd >= 0) -+ (void)close(fd); - - if (update) { - state += 2; -@@ -1012,7 +1013,7 @@ nsm_load_notify_list(nsm_populate_t func) - - static void - nsm_delete_host(const char *directory, const char *hostname, -- const char *mon_name, const char *my_name) -+ const char *mon_name, const char *my_name, const int chatty) - { - char line[LINELEN + 1 + SM_MAXSTRLEN + 2]; - char *outbuf = NULL; -@@ -1028,8 +1029,9 @@ nsm_delete_host(const char *directory, const char *hostname, - } - - if (stat(path, &stb) == -1) { -- xlog(L_ERROR, "Failed to delete: " -- "could not stat original file %s: %m", path); -+ if (chatty) -+ xlog(L_ERROR, "Failed to delete: " -+ "could not stat original file %s: %m", path); - goto out; - } - remaining = (size_t)stb.st_size + 1; -@@ -1108,13 +1110,14 @@ out: - * @hostname: '\0'-terminated C string containing hostname of record to delete - * @mon_name: '\0'-terminated C string containing monname of record to delete - * @my_name: '\0'-terminated C string containing myname of record to delete -+ * @chatty: should an error be logged if the monitor file doesn't exist? - * - */ - void - nsm_delete_monitored_host(const char *hostname, const char *mon_name, -- const char *my_name) -+ const char *my_name, const int chatty) - { -- nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name); -+ nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name, chatty); - } - - /** -@@ -1128,5 +1131,5 @@ void - nsm_delete_notified_host(const char *hostname, const char *mon_name, - const char *my_name) - { -- nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name); -+ nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name, 1); - } -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -index 0331926..03f96e9 100644 ---- a/systemd/Makefile.am -+++ b/systemd/Makefile.am -@@ -28,9 +28,13 @@ endif - if CONFIG_GSS - unit_files += \ - auth-rpcgss-module.service \ -- rpc-gssd.service \ -+ rpc-gssd.service -+ -+if CONFIG_SVCGSS -+unit_files += \ - rpc-svcgssd.service - endif -+endif - - EXTRA_DIST = $(unit_files) - -diff --git a/systemd/README b/systemd/README -index bbd7790..7c43df8 100644 ---- a/systemd/README -+++ b/systemd/README -@@ -53,7 +53,7 @@ client and systemd cannot specify is two-pronged reverse dependency. - (i.e. stop this unit if none of these units are running) - - Distro specific commandline configuration can be provided by --installing a script /usr/lib/systemd/scripts/nfs-utils_env.sh -+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. -diff --git a/systemd/nfs-config.service b/systemd/nfs-config.service -index 7f65305..bd69e84 100644 ---- a/systemd/nfs-config.service -+++ b/systemd/nfs-config.service -@@ -5,5 +5,9 @@ DefaultDependencies=no - - [Service] - Type=oneshot --RemainAfterExit=yes --ExecStart=/usr/lib/systemd/scripts/nfs-utils_env.sh -+# 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=/usr/libexec/nfs-utils/nfs-utils_env.sh -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 12b02f2..2ccdc63 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -1,13 +1,14 @@ - [Unit] - Description=NFS server and services - DefaultDependencies=no --Requires= network.target proc-fs-nfsd.mount rpcbind.service -+Requires= network.target proc-fs-nfsd.mount - Requires= nfs-mountd.service -+Wants=rpcbind.socket - Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service - - After= local-fs.target --After= network.target proc-fs-nfsd.mount rpcbind.service nfs-mountd.service -+After= network.target proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service - After= nfs-idmapd.service rpc-statd.service - Before= rpc-statd-notify.service - -diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service -index 14604d7..a02f5c4 100644 ---- a/systemd/rpc-statd.service -+++ b/systemd/rpc-statd.service -@@ -2,8 +2,8 @@ - Description=NFS status monitor for NFSv2/3 locking. - DefaultDependencies=no - Conflicts=umount.target --Requires=nss-lookup.target rpcbind.target --After=network.target nss-lookup.target rpcbind.target -+Requires=nss-lookup.target rpcbind.socket -+After=network.target nss-lookup.target rpcbind.socket - - PartOf=nfs-utils.service - -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 011bb42..4ca4bc4 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -150,6 +150,8 @@ Nfsv3ops = [ - 'COMMIT' - ] - -+# This list should be kept in-sync with the NFSPROC4_CLNT_* enum in -+# include/linux/nfs4.h in the kernel. - Nfsv4ops = [ - 'NULL', - 'READ', -@@ -204,7 +206,12 @@ Nfsv4ops = [ - 'FREE_STATEID', - 'GETDEVICELIST', - 'BIND_CONN_TO_SESSION', -- 'DESTROY_CLIENTID' -+ 'DESTROY_CLIENTID', -+ 'SEEK', -+ 'ALLOCATE', -+ 'DEALLOCATE', -+ 'LAYOUTSTATS', -+ 'CLONE' - ] - - class DeviceData: -@@ -563,7 +570,10 @@ class DeviceData: - for the nfsstat command. - """ - for op in new_stats.__rpc_data['ops']: -- self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) -+ try: -+ self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) -+ except KeyError: -+ continue - - def __print_rpc_op_stats(self, op, sample_time): - """Print generic stats for one RPC op -diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man -index fd38122..914b80f 100644 ---- a/utils/blkmapd/blkmapd.man -+++ b/utils/blkmapd/blkmapd.man -@@ -9,7 +9,7 @@ - .SH NAME - blkmapd \- pNFS block layout mapping daemon - .SH SYNOPSIS --.B "blkmapd [-d] [-f]" -+.B "blkmapd [-h] [-d] [-f]" - .SH DESCRIPTION - The - .B blkmapd -@@ -33,6 +33,9 @@ reflect the server topology, and passes these devices to the kernel for use - by the pNFS block layout client. - .SH OPTIONS - .TP -+.B -h -+Display usage message. -+.TP - .B -d - Performs device discovery only then exits. - .TP -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index b52afe2..052d582 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -51,6 +51,7 @@ - #include - - #include "device-discovery.h" -+#include "xcommon.h" - - #define EVENT_SIZE (sizeof(struct inotify_event)) - #define EVENT_BUFSIZE (1024 * EVENT_SIZE) -@@ -427,7 +428,10 @@ void sig_die(int signal) - BL_LOG_ERR("exit on signal(%d)\n", signal); - exit(1); - } -- -+static void usage(void) -+{ -+ fprintf(stderr, "Usage: blkmapd [-hdf]\n" ); -+} - /* Daemon */ - int main(int argc, char **argv) - { -@@ -435,7 +439,7 @@ int main(int argc, char **argv) - struct stat statbuf; - char pidbuf[64]; - -- while ((opt = getopt(argc, argv, "df")) != -1) { -+ while ((opt = getopt(argc, argv, "hdf")) != -1) { - switch (opt) { - case 'd': - dflag = 1; -@@ -443,6 +447,13 @@ int main(int argc, char **argv) - case 'f': - fg = 1; - break; -+ case 'h': -+ usage(); -+ exit(0); -+ default: -+ usage(); -+ exit(1); -+ - } - } - -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 8758231..a00b5ea 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -108,11 +108,14 @@ main(int argc, char **argv) - xlog_stderr(1); - xlog_syslog(0); - -- while ((c = getopt(argc, argv, "afhio:ruvs")) != EOF) { -+ while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) { - switch(c) { - case 'a': - f_all = 1; - break; -+ case 'd': -+ xlog_sconfig(optarg, 1); -+ break; - case 'f': - force_flush = 1; - break; -@@ -405,8 +408,17 @@ unexportfs_parsed(char *hname, char *path, int verbose) - hname = ai->ai_canonname; - } - -+ /* -+ * It's possible the specified path ends with a '/'. But -+ * the entry from exportlist won't has the trailing '/', -+ * so need to deal with it. -+ */ -+ size_t nlen = strlen(path); -+ while (path[nlen - 1] == '/') -+ nlen--; -+ - for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { -- if (path && strcmp(path, exp->m_export.e_path)) -+ if (path && strncmp(path, exp->m_export.e_path, nlen)) - continue; - if (htype != exp->m_client->m_type) - continue; -@@ -499,9 +511,10 @@ unexportfs(char *arg, int verbose) - - static int can_test(void) - { -- char buf[1024]; -+ char buf[1024] = { 0 }; - int fd; - int n; -+ size_t bufsiz = sizeof(buf); - - fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); - if (fd < 0) -@@ -514,9 +527,9 @@ static int can_test(void) - * commit 2f74f972 (sunrpc: prepare NFS for 2038). - */ - if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS) -- sprintf(buf, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); -+ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); - else -- sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); -+ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); - - n = write(fd, buf, strlen(buf)); - close(fd); -@@ -532,7 +545,8 @@ static int can_test(void) - - static int test_export(char *path, int with_fsid) - { -- char buf[1024]; -+ /* beside max path, buf size should take protocol str into account */ -+ char buf[NFS_MAXPATHLEN+1+64] = { 0 }; - char *bp = buf; - int len = sizeof(buf); - int fd, n; -@@ -571,8 +585,8 @@ validate_export(nfs_export *exp) - xlog(L_ERROR, "Failed to stat %s: %m", path); - return; - } -- if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { -- xlog(L_ERROR, "%s is neither a directory nor a file. " -+ if (!S_ISDIR(stb.st_mode)) { -+ xlog(L_ERROR, "%s is not a directory. " - "Remote access will fail", path); - return; - } -@@ -758,7 +772,8 @@ dumpopt(char c, char *fmt, ...) - static void - dump(int verbose, int export_format) - { -- char buf[1024]; -+ /* buf[] size should >= sizeof(struct exportent->e_path) */ -+ char buf[NFS_MAXPATHLEN+1] = { 0 }; - char *bp; - int len; - nfs_export *exp; -@@ -866,6 +881,6 @@ error(nfs_export *exp, int err) - static void - usage(const char *progname, int n) - { -- fprintf(stderr, "usage: %s [-afhioruvs] [host:/path]\n", progname); -+ fprintf(stderr, "usage: %s [-adfhioruvs] [host:/path]\n", progname); - exit(n); - } -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 75d952a..fdf9260 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -88,6 +88,9 @@ appropriate export entry for the host given in - to be added to the kernel's export table. - .SH OPTIONS - .TP -+.B \-d kind " or " \-\-debug kind -+Turn on debugging. Valid kinds are: all, auth, call, general and parse. -+.TP - .B -a - Export or unexport all directories. - .TP -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index cb040b3..3f5f59a 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -49,7 +49,8 @@ gssd_LDADD = \ - $(RPCSECGSS_LIBS) \ - $(KRBLIBS) \ - $(GSSAPI_LIBS) \ -- $(LIBTIRPC) -+ $(LIBTIRPC) \ -+ $(LIBPTHREAD) - - gssd_LDFLAGS = \ - $(KRBLDFLAGS) -diff --git a/utils/gssd/context_heimdal.c b/utils/gssd/context_heimdal.c -index 1e8738a..d07103b 100644 ---- a/utils/gssd/context_heimdal.c -+++ b/utils/gssd/context_heimdal.c -@@ -260,7 +260,7 @@ serialize_krb5_ctx(gss_ctx_id_t *_ctx, gss_buffer_desc *buf, int32_t *endtime) - if (write_heimdal_seq_key(&p, end, ctx)) goto out_err; - - buf->length = p - (char *)buf->value; -- printerr(2, "serialize_krb5_ctx: returning buffer " -+ printerr(4, "serialize_krb5_ctx: returning buffer " - "with %d bytes\n", buf->length); - - return 0; -diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index badbe88..5d77c21 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -206,7 +206,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, - if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; - - /* Protocol 0 here implies DES3 or RC4 */ -- printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); -+ printerr(4, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); - if (lctx->protocol == 0) { - enctype = lctx->rfc1964_kd.ctx_key.type; - keysize = lctx->rfc1964_kd.ctx_key.length; -@@ -219,7 +219,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, - keysize = lctx->cfx_kd.ctx_key.length; - } - } -- printerr(2, "%s: serializing key with enctype %d and size %d\n", -+ printerr(4, "%s: serializing key with enctype %d and size %d\n", - __FUNCTION__, enctype, keysize); - - if (WRITE_BYTES(&p, end, enctype)) goto out_err; -@@ -265,7 +265,7 @@ serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime) - gss_krb5_lucid_context_v1_t *lctx = 0; - int retcode = 0; - -- printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); -+ printerr(4, "DEBUG: %s: lucid version!\n", __FUNCTION__); - maj_stat = gss_export_lucid_sec_context(&min_stat, ctx, - 1, &return_ctx); - if (maj_stat != GSS_S_COMPLETE) { -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index e480349..3b4d147 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -87,7 +87,9 @@ unsigned int rpc_timeout = 5; - char *preferred_realm = NULL; - /* Avoid DNS reverse lookups on server names */ - static bool avoid_dns = true; -- -+int thread_started = false; -+pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER; -+pthread_cond_t pcond = PTHREAD_COND_INITIALIZER; - - TAILQ_HEAD(topdir_list_head, topdir) topdir_list; - -@@ -301,6 +303,22 @@ gssd_read_service_info(int dirfd, struct clnt_info *clp) - goto fail; - } - -+ /* -+ * The user space RPC library has no support for -+ * RPC-over-RDMA at this time, so change 'rdma' -+ * to 'tcp', and '20049' to '2049'. -+ */ -+ if (strcmp(protoname, "rdma") == 0) { -+ free(protoname); -+ protoname = strdup("tcp"); -+ if (!protoname) -+ goto fail; -+ free(port); -+ port = strdup("2049"); -+ if (!port) -+ goto fail; -+ } -+ - if (!gssd_addrstr_to_sockaddr((struct sockaddr *)&clp->addr, - address, port ? port : "")) - goto fail; -@@ -361,20 +379,91 @@ gssd_destroy_client(struct clnt_info *clp) - - static void gssd_scan(void); - -+static int -+start_upcall_thread(void (*func)(struct clnt_upcall_info *), void *info) -+{ -+ pthread_attr_t attr; -+ pthread_t th; -+ int ret; -+ -+ ret = pthread_attr_init(&attr); -+ if (ret != 0) { -+ printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n", -+ ret, strerror(errno)); -+ return ret; -+ } -+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -+ if (ret != 0) { -+ printerr(0, "ERROR: failed to create pthread attr: ret %d: " -+ "%s\n", ret, strerror(errno)); -+ return ret; -+ } -+ -+ ret = pthread_create(&th, &attr, (void *)func, (void *)info); -+ if (ret != 0) -+ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n", -+ ret, strerror(errno)); -+ return ret; -+} -+ -+static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp) -+{ -+ struct clnt_upcall_info *info; -+ -+ info = malloc(sizeof(struct clnt_upcall_info)); -+ if (info == NULL) -+ return NULL; -+ info->clp = clp; -+ -+ return 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. -+ */ - static void - gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) - { - struct clnt_info *clp = data; -+ struct clnt_upcall_info *info; -+ -+ info = alloc_upcall_info(clp); -+ if (info == NULL) -+ return; -+ -+ 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); -+ return; -+ } -+ info->lbuf[info->lbuflen-1] = 0; - -- handle_gssd_upcall(clp); -+ if (start_upcall_thread(handle_gssd_upcall, info)) -+ free(info); - } - - static void - gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) - { - struct clnt_info *clp = data; -+ struct clnt_upcall_info *info; - -- handle_krb5_upcall(clp); -+ info = alloc_upcall_info(clp); -+ if (info == NULL) -+ return; -+ -+ if (read(clp->krb5_fd, &info->uid, -+ 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); -+ return; -+ } -+ -+ if (start_upcall_thread(handle_krb5_upcall, info)) -+ free(info); - } - - static struct clnt_info * -@@ -400,8 +489,9 @@ gssd_get_clnt(struct topdir *tdi, const char *name) - - clp->wd = inotify_add_watch(inotify_fd, clp->relpath, IN_CREATE | IN_DELETE); - if (clp->wd < 0) { -- printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", -- clp->relpath, strerror(errno)); -+ if (errno != ENOENT) -+ printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", -+ clp->relpath, strerror(errno)); - goto out; - } - -@@ -556,7 +646,7 @@ gssd_scan_topdir(const char *name) - if (clp->scanned) - continue; - -- printerr(2, "destroying client %s\n", clp->relpath); -+ printerr(3, "destroying client %s\n", clp->relpath); - saveprev = clp->list.tqe_prev; - TAILQ_REMOVE(&tdi->clnt_list, clp, list); - gssd_destroy_client(clp); -@@ -716,7 +806,7 @@ gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data)) - - found: - if (!tdi) { -- printerr(1, "inotify event for unknown wd!!! - " -+ printerr(5, "inotify event for unknown wd!!! - " - "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", - ev->wd, ev->len > 0 ? ev->name : "", ev->mask); - rescan = true; -@@ -820,7 +910,7 @@ main(int argc, char *argv[]) - * the results of getpw*. - */ - if (setenv("HOME", "/", 1)) { -- printerr(1, "Unable to set $HOME: %s\n", strerror(errno)); -+ printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); - exit(1); - } - -@@ -865,14 +955,16 @@ main(int argc, char *argv[]) - progname = argv[0]; - - initerr(progname, verbosity, fg); --#ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL -- if (verbosity && rpc_verbosity == 0) -- rpc_verbosity = verbosity; -- authgss_set_debug_level(rpc_verbosity); -+#ifdef HAVE_LIBTIRPC_SET_DEBUG -+ /* -+ * Only set the libtirpc debug level if explicitly requested via -r. -+ */ -+ if (rpc_verbosity > 0) -+ libtirpc_set_debug(progname, rpc_verbosity, fg); - #else -- if (rpc_verbosity > 0) -- printerr(0, "Warning: rpcsec_gss library does not " -- "support setting debug level\n"); -+ if (rpc_verbosity > 0) -+ printerr(0, "Warning: libtirpc does not " -+ "support setting debug levels\n"); - #endif - - if (gssd_check_mechs() != 0) -@@ -884,19 +976,19 @@ main(int argc, char *argv[]) - - pipefs_dir = opendir(pipefs_path); - if (!pipefs_dir) { -- printerr(1, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); -+ printerr(0, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); - exit(EXIT_FAILURE); - } - - pipefs_fd = dirfd(pipefs_dir); - if (fchdir(pipefs_fd)) { -- printerr(1, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); -+ printerr(0, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); - exit(EXIT_FAILURE); - } - - inotify_fd = inotify_init1(IN_NONBLOCK); - if (inotify_fd == -1) { -- printerr(1, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); -+ printerr(0, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - -@@ -913,7 +1005,7 @@ main(int argc, char *argv[]) - - event_dispatch(); - -- printerr(1, "ERROR: event_dispatch() returned!\n"); -+ printerr(0, "ERROR: event_dispatch() returned!\n"); - return EXIT_FAILURE; - } - -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index c6937c5..f4f5975 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - - #ifndef GSSD_PIPEFS_DIR - #define GSSD_PIPEFS_DIR "/var/lib/nfs/rpc_pipefs" -@@ -48,7 +49,7 @@ - #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" - #define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" - #define GSSD_SERVICE_NAME "nfs" -- -+#define RPC_CHAN_BUF_SIZE 32768 - /* - * The gss mechanisms that we can handle - */ -@@ -61,6 +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; -@@ -80,8 +85,15 @@ struct clnt_info { - struct sockaddr_storage addr; - }; - --void handle_krb5_upcall(struct clnt_info *clp); --void handle_gssd_upcall(struct clnt_info *clp); -+struct clnt_upcall_info { -+ struct clnt_info *clp; -+ char lbuf[RPC_CHAN_BUF_SIZE]; -+ int lbuflen; -+ uid_t uid; -+}; -+ -+void handle_krb5_upcall(struct clnt_upcall_info *clp); -+void handle_gssd_upcall(struct clnt_upcall_info *clp); - - - #endif /* _RPC_GSSD_H_ */ -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 11168b2..d74d372 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -69,6 +69,7 @@ - #include - #include - #include -+#include - - #include "gssd.h" - #include "err_util.h" -@@ -78,7 +79,6 @@ - #include "nfsrpc.h" - #include "nfslib.h" - #include "gss_names.h" --#include "misc.h" - - /* Encryption types supported by the kernel rpcsec_gss code */ - int num_krb5_enctypes = 0; -@@ -150,7 +150,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - unsigned int timeout = context_timeout; - unsigned int buf_size = 0; - -- printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", -+ printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", - 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 + -@@ -189,7 +189,7 @@ do_error_downcall(int k5_fd, uid_t uid, int err) - unsigned int timeout = 0; - int zero = 0; - -- printerr(1, "doing error downcall\n"); -+ printerr(2, "doing error downcall\n"); - - if (WRITE_BYTES(&p, end, uid)) goto out_err; - if (WRITE_BYTES(&p, end, timeout)) goto out_err; -@@ -348,16 +348,9 @@ create_auth_rpc_client(struct clnt_info *clp, - printerr(2, "creating %s client for server %s\n", clp->protocol, - clp->servername); - -- if ((strcmp(clp->protocol, "tcp")) == 0) { -- protocol = IPPROTO_TCP; -- } else if ((strcmp(clp->protocol, "udp")) == 0) { -+ protocol = IPPROTO_TCP; -+ if ((strcmp(clp->protocol, "udp")) == 0) - protocol = IPPROTO_UDP; -- } else { -- printerr(0, "WARNING: unrecognized protocol, '%s', requested " -- "for connection to server %s for user with uid %d\n", -- clp->protocol, clp->servername, uid); -- goto out_fail; -- } - - switch (addr->sa_family) { - case AF_INET: -@@ -443,7 +436,7 @@ change_identity(uid_t uid) - struct passwd *pw; - - /* drop list of supplimentary groups first */ -- if (setgroups(0, NULL) != 0) { -+ if (syscall(SYS_setgroups, 0, 0) != 0) { - printerr(0, "WARNING: unable to drop supplimentary groups!"); - return errno; - } -@@ -460,20 +453,18 @@ change_identity(uid_t uid) - } - } - -- /* -- * Switch the GIDs. Note that we leave the saved-set-gid alone in an -- * attempt to prevent attacks via ptrace() -+ /* Switch the UIDs and GIDs. */ -+ /* For the threaded version we have to set uid,gid per thread instead -+ * of per process. glibc setresuid() when called from a thread, it'll -+ * send a signal to all other threads to synchronize the uid in all -+ * other threads. To bypass this, we have to call syscall() directly. - */ -- if (setresgid(pw->pw_gid, pw->pw_gid, -1) != 0) { -+ if (syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { - printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid); - return errno; - } - -- /* -- * Switch UIDs, but leave saved-set-uid alone to prevent ptrace() by -- * other processes running with this uid. -- */ -- if (setresuid(uid, uid, -1) != 0) { -+ if (syscall(SYS_setresuid, uid, uid, uid) != 0) { - printerr(0, "WARNING: Failed to setuid for user with uid %u\n", - uid); - return errno; -@@ -491,7 +482,7 @@ krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - char **dname; - int err, resp = -1; - -- printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", -+ printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n", - uid, tgtname); - - *chg_err = change_identity(uid); -@@ -538,7 +529,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - int nocache = 0; - int success = 0; - -- printerr(1, "krb5_use_machine_creds: uid %d tgtname %s\n", -+ printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n", - uid, tgtname); - - do { -@@ -555,7 +546,15 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - goto out; - } - for (ccname = credlist; ccname && *ccname; ccname++) { -- gssd_setup_krb5_machine_gss_ccache(*ccname); -+ u_int min_stat; -+ -+ if (gss_krb5_ccache_name(&min_stat, *ccname, NULL) != -+ GSS_S_COMPLETE) { -+ printerr(1, "WARNING: gss_krb5_ccache_name " -+ "with name '%s' failed (%s)\n", -+ *ccname, error_message(min_stat)); -+ continue; -+ } - if ((create_auth_rpc_client(clp, tgtname, rpc_clnt, - &auth, uid, - AUTHTYPE_KRB5, -@@ -564,7 +563,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - success++; - break; - } -- printerr(2, "WARNING: Failed to create machine krb5" -+ printerr(2, "WARNING: Failed to create machine krb5 " - "context with cred cache %s for server %s\n", - *ccname, clp->servername); - } -@@ -572,12 +571,13 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - if (!success) { - if(nocache == 0) { - nocache++; -- printerr(2, "WARNING: Machine cache prematurely" "expired or corrupted trying to" -- "recreate cache for server %s\n", -+ printerr(2, "WARNING: Machine cache prematurely " -+ "expired or corrupted trying to " -+ "recreate cache for server %s\n", - clp->servername); - } else { -- printerr(1, "WARNING: Failed to create machine" -- "krb5 context with any credentials" -+ printerr(1, "ERROR: Failed to create machine " -+ "krb5 context with any credentials " - "cache for server %s\n", - clp->servername); - goto out; -@@ -603,13 +603,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - gss_buffer_desc token; - int err, downcall_err = -EACCES; - OM_uint32 maj_stat, min_stat, lifetime_rec; -- pid_t pid, childpid = -1; - gss_name_t gacceptor = GSS_C_NO_NAME; - gss_OID mech; - gss_buffer_desc acceptor = {0}; - -- printerr(1, "handling krb5 upcall (%s)\n", clp->relpath); -- - token.length = 0; - token.value = NULL; - memset(&pd, 0, sizeof(struct authgss_private_data)); -@@ -635,41 +632,9 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - * used for this case is not important. - * - */ -- printerr(2, "%s: service is '%s'\n", __func__, -- service ? service : ""); - if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && - service == NULL)) { - -- /* already running as uid 0 */ -- if (uid == 0) -- goto no_fork; -- -- pid = fork(); -- switch(pid) { -- case 0: -- /* Child: fall through to rest of function */ -- childpid = getpid(); -- unsetenv("KRB5CCNAME"); -- printerr(1, "CHILD forked pid %d \n", childpid); -- break; -- case -1: -- /* fork() failed! */ -- printerr(0, "WARNING: unable to fork() to handle" -- "upcall: %s\n", strerror(errno)); -- return; -- default: -- /* Parent: just wait on child to exit and return */ -- do { -- pid = wait(&err); -- } while(pid == -1 && errno != -ECHILD); -- -- if (WIFSIGNALED(err)) -- printerr(0, "WARNING: forked child was killed" -- "with signal %d\n", WTERMSIG(err)); -- return; -- } --no_fork: -- - auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err, - &err, &rpc_clnt); - if (err) -@@ -683,9 +648,7 @@ no_fork: - if (auth == NULL) - goto out_return_error; - } else { -- printerr(1, "WARNING: Failed to create krb5 context " -- "for user with uid %d for server %s\n", -- uid, clp->servername); -+ /* krb5_not_machine_creds logs the error */ - goto out_return_error; - } - } -@@ -716,7 +679,7 @@ no_fork: - * try to use it after this point. - */ - if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { -- printerr(0, "WARNING: Failed to serialize krb5 context for " -+ printerr(1, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for server %s\n", - uid, clp->servername); - goto out_return_error; -@@ -737,11 +700,7 @@ out: - if (rpc_clnt) - clnt_destroy(rpc_clnt); - -- pid = getpid(); -- if (pid == childpid) -- exit(0); -- else -- return; -+ return; - - out_return_error: - do_error_downcall(fd, uid, downcall_err); -@@ -749,25 +708,21 @@ out_return_error: - } - - void --handle_krb5_upcall(struct clnt_info *clp) -+handle_krb5_upcall(struct clnt_upcall_info *info) - { -- uid_t uid; -+ struct clnt_info *clp = info->clp; - -- if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { -- printerr(0, "WARNING: failed reading uid from krb5 " -- "upcall pipe: %s\n", strerror(errno)); -- return; -- } -+ printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); - -- process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL); -+ process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL); -+ free(info); - } - - void --handle_gssd_upcall(struct clnt_info *clp) -+handle_gssd_upcall(struct clnt_upcall_info *info) - { -+ struct clnt_info *clp = info->clp; - uid_t uid; -- char lbuf[RPC_CHAN_BUF_SIZE]; -- int lbuflen = 0; - char *p; - char *mech = NULL; - char *uidstr = NULL; -@@ -775,19 +730,9 @@ handle_gssd_upcall(struct clnt_info *clp) - char *service = NULL; - char *enctypes = NULL; - -- printerr(1, "handling gssd upcall (%s)\n", clp->relpath); -- -- lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf)); -- if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { -- printerr(0, "WARNING: handle_gssd_upcall: " -- "failed reading request\n"); -- return; -- } -- lbuf[lbuflen-1] = 0; -- -- printerr(2, "%s: '%s'\n", __func__, lbuf); -+ printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); - -- for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) { -+ for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) { - if (!strncmp(p, "mech=", strlen("mech="))) - mech = p + strlen("mech="); - else if (!strncmp(p, "uid=", strlen("uid="))) -@@ -803,8 +748,8 @@ handle_gssd_upcall(struct clnt_info *clp) - if (!mech || strlen(mech) < 1) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to find gss mechanism name " -- "in upcall string '%s'\n", lbuf); -- return; -+ "in upcall string '%s'\n", info->lbuf); -+ goto out; - } - - if (uidstr) { -@@ -816,21 +761,21 @@ handle_gssd_upcall(struct clnt_info *clp) - if (!uidstr) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to find uid " -- "in upcall string '%s'\n", lbuf); -- return; -+ "in upcall string '%s'\n", info->lbuf); -+ goto out; - } - - if (enctypes && parse_enctypes(enctypes) != 0) { - printerr(0, "WARNING: handle_gssd_upcall: " - "parsing encryption types failed: errno %d\n", errno); -- return; -+ goto out; - } - - if (target && strlen(target) < 1) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to parse target name " -- "in upcall string '%s'\n", lbuf); -- return; -+ "in upcall string '%s'\n", info->lbuf); -+ goto out; - } - - /* -@@ -844,8 +789,8 @@ handle_gssd_upcall(struct clnt_info *clp) - if (service && strlen(service) < 1) { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed to parse service type " -- "in upcall string '%s'\n", lbuf); -- return; -+ "in upcall string '%s'\n", info->lbuf); -+ goto out; - } - - if (strcmp(mech, "krb5") == 0 && clp->servername) -@@ -856,5 +801,8 @@ handle_gssd_upcall(struct clnt_info *clp) - "received unknown gss mech '%s'\n", mech); - do_error_downcall(clp->gssd_fd, uid, -EACCES); - } -+out: -+ free(info); -+ return; - } - -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index ecf17a2..c1e4d2b 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -128,6 +128,7 @@ - - /* 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; - - #ifdef HAVE_SET_ALLOWABLE_ENCTYPES - int limit_to_legacy_enctypes = 0; -@@ -356,7 +357,7 @@ gssd_get_single_krb5_cred(krb5_context context, - */ - now += 300; - if (ple->ccname && ple->endtime > now && !nocache) { -- printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", -+ printerr(3, "INFO: Credentials in CC '%s' are good until %d\n", - ple->ccname, ple->endtime); - code = 0; - goto out; -@@ -383,7 +384,7 @@ gssd_get_single_krb5_cred(krb5_context context, - "tickets. May have problems behind a NAT.\n"); - #ifdef TEST_SHORT_LIFETIME - /* set a short lifetime (for debugging only!) */ -- printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); -+ printerr(1, "WARNING: Using (debug) short machine cred lifetime!\n"); - krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60); - #endif - opts = init_opts; -@@ -451,8 +452,7 @@ gssd_get_single_krb5_cred(krb5_context context, - } - - code = 0; -- printerr(2, "Successfully obtained machine credentials for " -- "principal '%s' stored in ccache '%s'\n", pname, cc_name); -+ printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name); - out: - #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS - if (init_opts) -@@ -468,37 +468,6 @@ gssd_get_single_krb5_cred(krb5_context context, - } - - /* -- * Depending on the version of Kerberos, we either need to use -- * a private function, or simply set the environment variable. -- */ --static void --gssd_set_krb5_ccache_name(char *ccname) --{ --#ifdef USE_GSS_KRB5_CCACHE_NAME -- u_int maj_stat, min_stat; -- -- printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n", -- ccname); -- maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL); -- if (maj_stat != GSS_S_COMPLETE) { -- printerr(0, "WARNING: gss_krb5_ccache_name with " -- "name '%s' failed (%s)\n", -- ccname, error_message(min_stat)); -- } --#else -- /* -- * Set the KRB5CCNAME environment variable to tell the krb5 code -- * which credentials cache to use. (Instead of using the private -- * function above for which there is no generic gssapi -- * equivalent.) -- */ -- printerr(2, "using environment variable to select krb5 ccache %s\n", -- ccname); -- setenv("KRB5CCNAME", ccname, 1); --#endif --} -- --/* - * Given a principal, find a matching ple structure - */ - static struct gssd_k5_kt_princ * -@@ -587,10 +556,12 @@ get_ple_by_princ(krb5_context context, krb5_principal princ) - - /* 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); - } -+ pthread_mutex_unlock(&ple_lock); - - return ple; - } -@@ -797,11 +768,11 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - char **realmnames = NULL; - char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; - char myhostad[NI_MAXHOST+1]; -- int i, j, retval; -+ int i, j, k, retval; - char *default_realm = NULL; - char *realm; - char *k5err = NULL; -- int tried_all = 0, tried_default = 0; -+ int tried_all = 0, tried_default = 0, tried_upper = 0; - krb5_principal princ; - const char *notsetstr = "not set"; - char *adhostoverride; -@@ -835,7 +806,6 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - strcpy(myhostad, myhostname); - for (i = 0; myhostad[i] != 0; ++i) { - if (myhostad[i] == '.') break; -- myhostad[i] = toupper(myhostad[i]); - } - myhostad[i] = '$'; - myhostad[i+1] = 0; -@@ -936,6 +906,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - k5err = gssd_k5_err_msg(context, code); - printerr(3, "%s while getting keytab entry for '%s'\n", - k5err, spn); -+ /* -+ * We tried the active directory machine account -+ * with the hostname part as-is and failed... -+ * convert it to uppercase and try again before -+ * moving on to the svcname -+ */ -+ if (strcmp(svcnames[j],"$") == 0 && !tried_upper) { -+ for (k = 0; myhostad[k] != '$'; ++k) { -+ myhostad[k] = toupper(myhostad[k]); -+ } -+ j--; -+ tried_upper = 1; -+ } - } else { - printerr(3, "Success getting keytab entry for '%s'\n",spn); - retval = 0; -@@ -1080,9 +1063,10 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) - const char *cctype; - struct dirent *d; - int err, i, j; -+ u_int maj_stat, min_stat; - -- printerr(2, "getting credentials for client with uid %u for " -- "server %s\n", uid, servername); -+ printerr(3, "looking for client creds with uid %u for " -+ "server %s in %s\n", uid, servername, dirpattern); - - for (i = 0, j = 0; dirpattern[i] != '\0'; i++) { - switch (dirpattern[i]) { -@@ -1115,22 +1099,16 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) - - printerr(2, "using %s as credentials cache for client with " - "uid %u for server %s\n", buf, uid, servername); -- gssd_set_krb5_ccache_name(buf); -- return 0; --} - --/* -- * Let the gss code know where to find the machine credentials ccache. -- * -- * Returns: -- * void -- */ --void --gssd_setup_krb5_machine_gss_ccache(char *ccname) --{ -- printerr(2, "using %s as credentials cache for machine creds\n", -- ccname); -- gssd_set_krb5_ccache_name(ccname); -+ printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", -+ buf); -+ maj_stat = gss_krb5_ccache_name(&min_stat, buf, NULL); -+ if (maj_stat != GSS_S_COMPLETE) { -+ printerr(0, "ERROR: unable to get user cred cache '%s' " -+ "failed (%s)\n", buf, error_message(min_stat)); -+ return maj_stat; -+ } -+ return 0; - } - - /* -@@ -1398,16 +1376,21 @@ gssd_acquire_krb5_cred(gss_cred_id_t *gss_cred) - int - gssd_acquire_user_cred(gss_cred_id_t *gss_cred) - { -- OM_uint32 min_stat; -+ OM_uint32 maj_stat, min_stat; - int ret; - - ret = gssd_acquire_krb5_cred(gss_cred); - - /* force validation of cred to check for expiry */ - if (ret == 0) { -- if (gss_inquire_cred(&min_stat, *gss_cred, NULL, NULL, -- NULL, NULL) != GSS_S_COMPLETE) -- ret = -1; -+ maj_stat = gss_inquire_cred(&min_stat, *gss_cred, -+ NULL, NULL, NULL, NULL); -+ if (maj_stat != GSS_S_COMPLETE) { -+ if (get_verbosity() > 0) -+ pgsserr("gss_inquire_cred", -+ maj_stat, min_stat, &krb5oid); -+ ret = -1; -+ } - } - - return ret; -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index a319588..e3bbb07 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -27,7 +27,6 @@ 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_setup_krb5_machine_gss_ccache(char *servername); - void gssd_destroy_krb5_machine_creds(void); - int gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -@@ -55,8 +54,6 @@ int limit_krb5_enctypes(struct rpc_gss_sec *sec); - #define k5_free_unparsed_name(ctx, name) free(name) - #define k5_free_default_realm(ctx, realm) free(realm) - #define k5_free_kt_entry(ctx, kte) krb5_kt_free_entry((ctx),(kte)) --#undef USE_GSS_KRB5_CCACHE_NAME --#define USE_GSS_KRB5_CCACHE_NAME 1 - #endif - - #endif /* KRB5_UTIL_H */ -diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c -index f1b4347..0fe7c6d 100644 ---- a/utils/gssd/svcgssd.c -+++ b/utils/gssd/svcgssd.c -@@ -135,6 +135,13 @@ main(int argc, char *argv[]) - if (verbosity && rpc_verbosity == 0) - rpc_verbosity = verbosity; - authgss_set_debug_level(rpc_verbosity); -+#elif HAVE_LIBTIRPC_SET_DEBUG -+ /* -+ * Only set the libtirpc debug level if explicitly requested via -r... -+ * svcgssd is chatty enough as it is. -+ */ -+ if (rpc_verbosity > 0) -+ libtirpc_set_debug(progname, rpc_verbosity, fg); - #else - if (rpc_verbosity > 0) - printerr(0, "Warning: rpcsec_gss library does not " -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 689608a..f4e083a 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -199,6 +199,12 @@ flush_nfsd_idmap_cache(void) - return ret; - } - -+void usage(char *progname) -+{ -+ fprintf(stderr, "Usage: %s [-hfvCS] [-p path] [-c path]\n", -+ basename(progname)); -+} -+ - int - main(int argc, char **argv) - { -@@ -225,16 +231,18 @@ main(int argc, char **argv) - progname = argv[0]; - xlog_open(progname); - --#define GETOPTSTR "vfd:p:U:G:c:CS" -+#define GETOPTSTR "hvfd:p:U:G:c:CS" - opterr=0; /* Turn off error messages */ - while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { - if (opt == 'c') - conf_path = optarg; - if (opt == '?') { - if (strchr(GETOPTSTR, optopt)) -- errx(1, "'-%c' option requires an argument.", optopt); -+ warnx("'-%c' option requires an argument.", optopt); - else -- errx(1, "'-%c' is an invalid argument.", optopt); -+ warnx("'-%c' is an invalid argument.", optopt); -+ usage(progname); -+ exit(1); - } - } - optind = 1; -@@ -276,6 +284,9 @@ main(int argc, char **argv) - case 'S': - clientstart = 0; - break; -+ case 'h': -+ usage(progname); -+ exit(0); - default: - break; - } -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index c809f78..b9200c7 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -10,8 +10,11 @@ - .Sh SYNOPSIS - .\" For a program: program [-abc] file ... - .Nm rpc.idmapd --.Op Fl v -+.Op Fl h - .Op Fl f -+.Op Fl v -+.Op Fl C -+.Op Fl S - .Op Fl p Ar path - .Op Fl c Ar path - .Sh DESCRIPTION -@@ -32,6 +35,8 @@ program. - .Pp - The options are as follows: - .Bl -tag -width Ds_imagedir -+.It Fl h -+Display usage message. - .It Fl v - Increases the verbosity level (can be specified multiple times). - .It Fl f -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index fa46d54..1f01f7f 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -208,6 +208,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - - if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) { - nfs_error(_("%s: no mount point provided"), progname); -+ umount_usage(); - return EX_USAGE; - } - -@@ -329,6 +330,7 @@ static int mount_main(struct libmnt_context *cxt, int argc, char **argv) - - if (!mount_point) { - nfs_error(_("%s: no mount point provided"), progname); -+ mount_usage(); - goto err; - } - if (!spec) { -diff --git a/utils/mount/network.c b/utils/mount/network.c -index b5ed850..0d12613 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -92,6 +92,7 @@ static const char *nfs_version_opttbl[] = { - "v4", - "vers", - "nfsvers", -+ "minorversion", - NULL, - }; - -@@ -793,6 +794,8 @@ int start_statd(void) - if (stat(START_STATD, &stb) == 0) { - if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) { - int cnt = STATD_TIMEOUT * 10; -+ int status = 0; -+ char * const envp[1] = { NULL }; - const struct timespec ts = { - .tv_sec = 0, - .tv_nsec = 100000000, -@@ -800,14 +803,19 @@ int start_statd(void) - pid_t pid = fork(); - switch (pid) { - case 0: /* child */ -- execl(START_STATD, START_STATD, NULL); -+ setgid(0); -+ setuid(0); -+ execle(START_STATD, START_STATD, NULL, envp); - exit(1); - case -1: /* error */ - nfs_error(_("%s: fork failed: %s"), - progname, strerror(errno)); - break; - default: /* parent */ -- waitpid(pid, NULL,0); -+ if (waitpid(pid, &status,0) == pid && -+ status == 0) -+ /* assume it worked */ -+ return 1; - break; - } - while (1) { -@@ -1272,7 +1280,11 @@ nfs_nfs_version(struct mount_options *options, struct nfs_version *version) - if (!(version->major = strtol(version_val, &cptr, 10))) - goto ret_error; - -- if (version->major < 4) -+ if (strcmp(nfs_version_opttbl[i], "minorversion") == 0) { -+ version->v_mode = V_SPECIFIC; -+ version->minor = version->major; -+ version->major = 4; -+ } else if (version->major < 4) - version->v_mode = V_SPECIFIC; - - if (*cptr == '.') { -@@ -1626,7 +1638,10 @@ int nfs_options2pmap(struct mount_options *options, - return 0; - if (!nfs_nfs_version(options, &version)) - return 0; -- nfs_pmap->pm_vers = version.major; -+ if (version.v_mode == V_DEFAULT) -+ nfs_pmap->pm_vers = 0; -+ else -+ nfs_pmap->pm_vers = version.major; - if (!nfs_nfs_protocol(options, &nfs_pmap->pm_prot)) - return 0; - if (!nfs_nfs_port(options, &nfs_pmap->pm_port)) -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index e541cdc..7cad556 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -1521,8 +1521,8 @@ but it does not protect their sideband protocols. - .P - The - .B sec --mount option specifies the security flavor --that is in effect on a given NFS mount point. -+mount option specifies the security flavor used for operations -+on behalf of users on that NFS mount point. - Specifying - .B sec=krb5 - provides cryptographic proof of a user's identity in each RPC request. -@@ -1550,7 +1550,7 @@ expect some performance impact - when using integrity checking or encryption. - Similar support for other forms of cryptographic security - is also available. --.P -+.SS "NFS version 4 filesystem crossing" - The NFS version 4 protocol allows - a client to renegotiate the security flavor - when the client crosses into a new filesystem on the server. -@@ -1560,6 +1560,59 @@ Such negotiation typically occurs when a client crosses - from a server's pseudo-fs - into one of the server's exported physical filesystems, - which often have more restrictive security settings than the pseudo-fs. -+.SS "NFS version 4 Leases" -+In NFS version 4, a lease is a period of time during which a server -+irrevocably grants a file lock to a client. -+If the lease expires, the server is allowed to revoke that lock. -+Clients periodically renew their leases to prevent lock revocation. -+.P -+After an NFS version 4 server reboots, each client tells the -+server about all file open and lock state under its lease -+before operation can continue. -+If the client reboots, the server frees all open and lock state -+associated with that client's lease. -+.P -+As part of establishing a lease, therefore, -+a client must identify itself to a server. -+A fixed string is used to distinguish that client from -+others, and a changeable verifier is used to indicate -+when the client has rebooted. -+.P -+A client uses a particular security flavor and principal -+when performing the operations to establish a lease. -+If two clients happen to present the same identity string, -+a server can use their principals to detect that they are -+different clients, and prevent one client from interfering -+with the other's lease. -+.P -+The Linux NFS client establishes one lease for each server. -+Lease management operations, such as lease renewal, are not -+done on behalf of a particular file, lock, user, or mount -+point, but on behalf of the whole client that owns that lease. -+These operations must use the same security flavor and -+principal that was used when the lease was established, -+even across client reboots. -+.P -+When Kerberos is configured on a Linux NFS client -+(i.e., there is a -+.I /etc/krb5.keytab -+on that client), the client attempts to use a Kerberos -+security flavor for its lease management operations. -+This provides strong authentication of the client to -+each server it contacts. -+By default, the client uses the -+.I host/ -+or -+.I nfs/ -+service principal in its -+.I /etc/krb5.keytab -+for this purpose. -+.P -+If the client has Kerberos configured, but the server -+does not, or if the client does not have a keytab or -+the requisite service principals, the client uses -+.I AUTH_SYS -+and UID 0 for lease management. - .SS "Using non-privileged source ports" - NFS clients usually communicate with NFS servers via network sockets. - Each end of a socket is assigned a port value, which is simply a number -diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c -index d64b83d..0d3bcb9 100644 ---- a/utils/mount/parse_dev.c -+++ b/utils/mount/parse_dev.c -@@ -118,7 +118,8 @@ static int nfs_parse_simple_hostname(const char *dev, - if (pathname) { - *pathname = strndup(colon, path_len); - if (*pathname == NULL) { -- free(*hostname); -+ if (hostname) -+ free(*hostname); - return nfs_pdn_nomem_err(); - } - } -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index c8f5a6d..d60b484 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -383,13 +383,26 @@ static int nfs_validate_options(struct nfsmount_info *mi) - if (!nfs_nfs_proto_family(mi->options, &family)) - return 0; - -- hint.ai_family = (int)family; -- error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); -- if (error != 0) { -- nfs_error(_("%s: Failed to resolve server %s: %s"), -- progname, mi->hostname, gai_strerror(error)); -- mi->address = NULL; -- return 0; -+ /* -+ * A remount is not going to be able to change the server's address, -+ * nor should we try to resolve another address for the server as we -+ * may end up with a different address. -+ */ -+ if (mi->flags & MS_REMOUNT) { -+ po_remove_all(mi->options, "addr"); -+ } else { -+ hint.ai_family = (int)family; -+ error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); -+ if (error != 0) { -+ nfs_error(_("%s: Failed to resolve server %s: %s"), -+ progname, mi->hostname, gai_strerror(error)); -+ mi->address = NULL; -+ return 0; -+ } -+ -+ if (!nfs_append_addr_option(mi->address->ai_addr, -+ mi->address->ai_addrlen, mi->options)) -+ return 0; - } - - if (!nfs_set_version(mi)) -@@ -398,10 +411,6 @@ static int nfs_validate_options(struct nfsmount_info *mi) - if (!nfs_append_sloppy_option(mi->options)) - return 0; - -- if (!nfs_append_addr_option(mi->address->ai_addr, -- mi->address->ai_addrlen, mi->options)) -- return 0; -- - return 1; - } - -@@ -841,6 +850,9 @@ check_result: - case EPROTONOSUPPORT: - /* A clear indication that the server or our - * client does not support NFS version 4 and minor */ -+ case EINVAL: -+ /* A less clear indication that our client -+ * does not support NFSv4 minor version. */ - if (mi->version.v_mode == V_GENERAL && - mi->version.minor == 0) - return result; -@@ -957,6 +969,15 @@ static int nfsmount_fg(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -+ if (errno == EBUSY) -+ /* The only cause of EBUSY is if exactly the desired -+ * filesystem is already mounted. That can arguably -+ * be seen as success. "mount -a" tries to optimise -+ * out this case but sometimes fails. Help it out -+ * by pretending everything is rosy -+ */ -+ return EX_SUCCESS; -+ - if (nfs_is_permanent_error(errno)) - break; - -diff --git a/utils/mount/utils.c b/utils/mount/utils.c -index 92662ed..865a4a0 100644 ---- a/utils/mount/utils.c -+++ b/utils/mount/utils.c -@@ -110,7 +110,7 @@ void mount_usage(void) - void umount_usage(void) - { - printf(_("usage: %s dir [-fvnrlh]\n"), progname); -- printf(_("options:\n\t-f\t\tforce unmount\n")); -+ printf(_("options:\n\t-f\tforce unmount\n")); - printf(_("\t-v\tverbose\n")); - printf(_("\t-n\tDo not update /etc/mtab\n")); - printf(_("\t-r\tremount\n")); -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index 330cab5..894a7a5 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -85,7 +85,7 @@ auth_reload() - { - struct stat stb; - static ino_t last_inode; -- static int last_fd; -+ static int last_fd = -1; - static unsigned int counter; - int fd; - -@@ -93,11 +93,22 @@ auth_reload() - xlog(L_FATAL, "couldn't open %s", _PATH_ETAB); - } else if (fstat(fd, &stb) < 0) { - xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB); -- } else if (stb.st_ino == last_inode) { -+ close(fd); -+ } else if (last_fd != -1 && stb.st_ino == last_inode) { -+ /* We opened the etab file before, and its inode -+ * number hasn't changed since then. -+ */ - close(fd); - return counter; - } else { -- close(last_fd); -+ /* Need to process entries from the etab file. Close -+ * the file descriptor from the previous open (last_fd), -+ * and keep the current file descriptor open to prevent -+ * the file system reusing the current inode number -+ * (last_inode). -+ */ -+ if (last_fd != -1) -+ close(last_fd); - last_fd = fd; - last_inode = stb.st_ino; - } -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 7847446..ec86a22 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -31,6 +31,7 @@ - #include "mountd.h" - #include "fsloc.h" - #include "pseudoflavors.h" -+#include "xcommon.h" - - #ifdef USE_BLKID - #include "blkid/blkid.h" -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 9fe0f40..063da26 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -794,9 +794,10 @@ main(int argc, char **argv) - } - - /* No more arguments allowed. */ -- if (optind != argc || !version_any()) -+ if (optind != argc || !version_any()) { -+ fprintf(stderr, "%s: No protocol versions specified!\n", progname); - usage(progname, 1); -- -+ } - if (chdir(state_dir)) { - fprintf(stderr, "%s: chdir(%s) failed: %s\n", - progname, state_dir, strerror(errno)); -@@ -910,7 +911,8 @@ usage(const char *prog, int n) - " [-o num|--descriptors num] [-f exports-file|--exports-file=file]\n" - " [-p|--port port] [-V version|--nfs-version version]\n" - " [-N version|--no-nfs-version version] [-n|--no-tcp]\n" --" [-H ha-callout-prog] [-s|--state-directory-path path]\n" --" [-g|--manage-gids] [-t num|--num-threads=num] [-u|--no-udp]\n", prog); -+" [-H prog |--ha-callout prog] [-r |--reverse-lookup]\n" -+" [-s|--state-directory-path path] [-g|--manage-gids]\n" -+" [-t num|--num-threads=num] [-u|--no-udp]\n", prog); - exit(n); - } -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index 7c5bfbe..66e3bba 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -115,10 +115,7 @@ must be invoked with the option - .B \-n " or " \-\-no-tcp - Don't advertise TCP for mount. - .TP --.B \-P --Ignored (compatibility with unfsd??). --.TP --.B \-p num " or " \-\-port num -+.B \-p num " or " \-P num " or " \-\-port num - Specifies the port number used for RPC listener sockets. - If this option is not specified, - .B rpc.mountd -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index a2b11d8..dcb430a 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -168,22 +168,22 @@ nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port) - continue; - } - -- xlog(D_GENERAL, "Creating %s %s socket.", family, proto); -- - /* open socket and prepare to hand it off to kernel */ - sockfd = socket(addr->ai_family, addr->ai_socktype, - addr->ai_protocol); - if (sockfd < 0) { -- if (errno == EAFNOSUPPORT) -- xlog(L_NOTICE, "address family %s not " -- "supported by protocol %s", -- family, proto); -- else -+ if (errno != EAFNOSUPPORT) { - xlog(L_ERROR, "unable to create %s %s socket: " - "errno %d (%m)", family, proto, errno); -- rc = errno; -- goto error; -+ rc = errno; -+ goto error; -+ } -+ addr = addr->ai_next; -+ continue; - } -+ -+ xlog(D_GENERAL, "Created %s %s socket.", family, proto); -+ - #ifdef IPV6_SUPPORTED - if (addr->ai_family == AF_INET6 && - setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) { -@@ -282,7 +282,7 @@ nfssvc_set_rdmaport(const char *port) - int fd; - - if (sv) -- nport = sv->s_port; -+ nport = ntohs(sv->s_port); - else { - char *ep; - nport = strtol(port, &ep, 10); -diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man -index c37c9a8..4b8f4d7 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.man -+++ b/utils/nfsdcltrack/nfsdcltrack.man -@@ -22,7 +22,7 @@ nfsdcltrack \- NFSv4 Client Tracking Callout Program - nfsdcltrack [\-d] [\-f] [\-s stable storage dir] - .SH "DESCRIPTION" - .IX Header "DESCRIPTION" --nfsdcltack is the NFSv4 client tracking callout program. It is not necessary -+nfsdcltrack is the NFSv4 client tracking callout program. It is not necessary - to install this program on machines that are not acting as NFSv4 servers. - .PP - When a network partition is combined with a server reboot, there are -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 507193b..63545fc 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -17,7 +17,7 @@ - #include "conffile.h" - - int verbose = 0; --char *usage = "Usage: %s [-v] [-c || [-u|-g|-r key] || -d || -l || [-t timeout] key desc]"; -+char *usage = "Usage: %s [-vh] [-c || [-u|-g|-r key] || -d || -l || [-t timeout] key desc]"; - - #define MAX_ID_LEN 11 - #define IDMAP_NAMESZ 128 -@@ -80,8 +80,9 @@ static int keyring_clear(const char *keyring) - - key = find_key_by_type_and_desc("keyring", keyring, 0); - if (key == -1) { -- xlog_err("'%s' keyring was not found.", keyring); -- return EXIT_FAILURE; -+ if (verbose) -+ xlog_warn("'%s' keyring was not found.", keyring); -+ return EXIT_SUCCESS; - } - - if (keyctl_clear(key) < 0) { -@@ -89,10 +90,9 @@ static int keyring_clear(const char *keyring) - (unsigned int)key); - return EXIT_FAILURE; - } -- -+ - if (verbose) - xlog_warn("'%s' cleared", keyring); -- - return EXIT_SUCCESS; - } - -@@ -369,7 +369,7 @@ int main(int argc, char **argv) - - xlog_open(progname); - -- while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) { -+ while ((opt = getopt(argc, argv, "hdu:g:r:ct:vl")) != -1) { - switch (opt) { - case 'd': - display++; -@@ -398,12 +398,18 @@ int main(int argc, char **argv) - case 't': - timeout = atoi(optarg); - break; -+ case 'h': - default: - xlog_warn(usage, progname); -- break; -+ exit(opt == 'h' ? 0 : 1); - } - } - -+ if (geteuid() != 0) { -+ xlog_err("Must be run as root."); -+ return EXIT_FAILURE; -+ } -+ - if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF))) { - xlog_errno(rc, "Unable to create name to user id mappings."); - return EXIT_FAILURE; -@@ -423,9 +429,9 @@ int main(int argc, char **argv) - return keyring_clear(DEFAULT_KEYRING); - } - -- xlog_stderr(0); -+ xlog_stderr(verbose); - if ((argc - optind) != 2) { -- xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn("Bad arg count. Check /etc/request-key.conf"); - xlog_warn(usage, progname); - return EXIT_FAILURE; - } -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 0275bdf..2f17cf2 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -15,6 +15,8 @@ nfsidmap \- The NFS idmapper upcall program - .B "nfsidmap -d" - .br - .B "nfsidmap -l" -+.br -+.B "nfsidmap -h" - .SH DESCRIPTION - The NFSv4 protocol represents the local system's UID and GID values - on the wire as strings of the form -@@ -71,6 +73,9 @@ Display the system's effective NFSv4 domain name on - .B -g user - Revoke the gid key of the given user. - .TP -+.B -h -+Display usage message. -+.TP - .B -l - Display on - .I stdout -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index 9f481db..8376347 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -31,8 +31,8 @@ enum { - SRVPROC3_SZ = 22, - CLTPROC3_SZ = 22, - SRVPROC4_SZ = 2, -- CLTPROC4_SZ = 49, -- SRVPROC4OPS_SZ = 59, -+ CLTPROC4_SZ = 59, -+ SRVPROC4OPS_SZ = 71, - }; - - static unsigned int srvproc2info[SRVPROC2_SZ+2], -@@ -127,19 +127,30 @@ static const char * nfscltproc4name[CLTPROC4_SZ] = { - "remove", "rename", "link", "symlink", "create", "pathconf", - "statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl", - "setacl", "fs_locations", -- "rel_lkowner", "secinfo", -+ "rel_lkowner", "secinfo", "fsid_present", - /* nfsv4.1 client ops */ - "exchange_id", -- "create_ses", -- "destroy_ses", -+ "create_session", -+ "destroy_session", - "sequence", -- "get_lease_t", -+ "get_lease_time", - "reclaim_comp", - "layoutget", - "getdevinfo", - "layoutcommit", - "layoutreturn", -- "getdevlist", -+ "secinfo_no", -+ "test_stateid", -+ "free_stateid", -+ "getdevicelist", -+ "bind_conn_to_ses", -+ "destroy_clientid", -+ /* nfsv4.2 client ops */ -+ "seek", -+ "allocate", -+ "deallocate", -+ "layoutstats", -+ "clone", - }; - - static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = { -@@ -170,6 +181,19 @@ static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = { - "want_deleg", - "destroy_clid", - "reclaim_comp", -+ /* nfsv4.2 server ops */ -+ "allocate", -+ "copy", -+ "copy_notify", -+ "deallocate", -+ "ioadvise", -+ "layouterror", -+ "layoutstats", -+ "offloadcancel", -+ "offloadstatus", -+ "readplus", -+ "seek", -+ "write_same", - }; - - #define LABEL_srvnet "Server packet stats:\n" -@@ -823,13 +847,13 @@ print_callstats(const char *hdr, const char **names, - total += info[i]; - if (!total) - total = 1; -- for (i = 0; i < nr; i += 6) { -- for (j = 0; j < 6 && i + j < nr; j++) -- printf("%-13s", names[i+j]); -+ for (i = 0; i < nr; i += 5) { -+ for (j = 0; j < 5 && i + j < nr; j++) -+ printf("%-17s", names[i+j]); - printf("\n"); -- for (j = 0; j < 6 && i + j < nr; j++) { -+ for (j = 0; j < 5 && i + j < nr; j++) { - pct = ((unsigned long long) info[i+j]*100)/total; -- printf("%-8u%3llu%% ", info[i+j], pct); -+ printf("%-8u%3llu%% ", info[i+j], pct); - } - printf("\n"); - } -diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c -index c61087c..8cccdb8 100644 ---- a/utils/statd/hostname.c -+++ b/utils/statd/hostname.c -@@ -180,9 +180,6 @@ get_nameinfo(const struct sockaddr *sap, - * Incoming hostnames are looked up to determine the canonical hostname, - * and incoming presentation addresses are converted to canonical - * hostnames. -- * -- * We won't monitor peers that don't have a reverse map. The canonical -- * name gives us a key for our monitor list. - */ - __attribute__((__malloc__)) - char * -@@ -207,7 +204,7 @@ statd_canonical_name(const char *hostname) - result = get_nameinfo(ai->ai_addr, ai->ai_addrlen, - buf, (socklen_t)sizeof(buf)); - freeaddrinfo(ai); -- if (!result) -+ if (!result || buf[0] == '\0') - /* OK to use presentation address, - * if no reverse map exists */ - return strdup(hostname); -diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c -index 286a5e2..45c4346 100644 ---- a/utils/statd/monitor.c -+++ b/utils/statd/monitor.c -@@ -72,6 +72,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - }; - char *dnsname = NULL; -+ int existing = 0; - - xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name); - -@@ -148,17 +149,26 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - if (statd_matchhostname(NL_MY_NAME(clnt), my_name) && - NL_MY_PROC(clnt) == id->my_proc && - NL_MY_PROG(clnt) == id->my_prog && -- NL_MY_VERS(clnt) == id->my_vers && -- memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) { -- /* Hey! We already know you guys! */ -- xlog(D_GENERAL, -- "Duplicate SM_MON request for %s " -- "from procedure on %s", -- mon_name, my_name); -+ NL_MY_VERS(clnt) == id->my_vers) { -+ if (memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE)) { -+ xlog(D_GENERAL, -+ "Received SM_MON request with new " -+ "cookie for %s from procedure on %s", -+ mon_name, my_name); -+ -+ existing = 1; -+ break; -+ } else { -+ /* Hey! We already know you guys! */ -+ xlog(D_GENERAL, -+ "Duplicate SM_MON request for %s " -+ "from procedure on %s", -+ mon_name, my_name); - -- /* But we'll let you pass anyway. */ -- free(dnsname); -- goto success; -+ /* But we'll let you pass anyway. */ -+ free(dnsname); -+ goto success; -+ } - } - clnt = NL_NEXT(clnt); - } -@@ -167,7 +177,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - * We're committed...ignoring errors. Let's hope that a malloc() - * doesn't fail. (I should probably fix this assumption.) - */ -- if (!(clnt = nlist_new(my_name, mon_name, 0))) { -+ if (!existing && !(clnt = nlist_new(my_name, mon_name, 0))) { - free(dnsname); - xlog_warn("out of memory"); - goto failure; -@@ -180,8 +190,11 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - clnt->dns_name = dnsname; - - /* -- * Now, Create file on stable storage for host. -+ * Now, Create file on stable storage for host, first deleting any -+ * existing records on file. - */ -+ nsm_delete_monitored_host(dnsname, mon_name, my_name, 0); -+ - if (!nsm_insert_monitored_host(dnsname, - (struct sockaddr *)(char *)&my_addr, argp)) { - nlist_free(NULL, clnt); -@@ -190,7 +203,8 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) - - /* PRC: do the HA callout: */ - ha_callout("add-client", mon_name, my_name, -1); -- nlist_insert(&rtnl, clnt); -+ if (!existing) -+ nlist_insert(&rtnl, clnt); - xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name); - success: - result.res_stat = STAT_SUCC; -@@ -310,7 +324,7 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp) - ha_callout("del-client", mon_name, my_name, -1); - - nsm_delete_monitored_host(clnt->dns_name, -- mon_name, my_name); -+ mon_name, my_name, 1); - nlist_free(&rtnl, clnt); - - return (&result); -@@ -365,7 +379,7 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp) - /* PRC: do the HA callout: */ - ha_callout("del-client", mon_name, my_name, -1); - nsm_delete_monitored_host(clnt->dns_name, -- mon_name, my_name); -+ mon_name, my_name, 1); - nlist_free(&rtnl, clnt); - ++count; - clnt = temp; -diff --git a/utils/statd/rmtcall.c b/utils/statd/rmtcall.c -index 45c84f9..c4f6364 100644 ---- a/utils/statd/rmtcall.c -+++ b/utils/statd/rmtcall.c -@@ -113,7 +113,6 @@ statd_get_socket(void) - if (sockfd < 0) - return -1; - -- FD_SET(sockfd, &SVC_FDSET); - return sockfd; - } - -diff --git a/utils/statd/start-statd b/utils/statd/start-statd -index 14369e5..2fd6039 100755 ---- a/utils/statd/start-statd -+++ b/utils/statd/start-statd -@@ -6,11 +6,23 @@ - # site. - PATH="/sbin:/usr/sbin:/bin:/usr/bin" - -+# Use flock to serialize the running of this script -+exec 200> /var/run/rpc.statd.lock -+flock -e 200 -+ -+if [ -s /var/run/rpc.statd.pid ] && -+ [ 1`cat /var/run/rpc.statd.pid` -gt 1 ] && -+ kill -0 `cat /var/run/rpc.statd.pid` > /dev/null 2>&1 -+then -+ # statd already running - must have been slow to respond. -+ exit 0 -+fi - # First try systemd if it's installed. - if [ -d /run/systemd/system ]; then - # Quit only if the call worked. - systemctl start rpc-statd.service && exit - fi - -+cd / - # Fall back to launching it ourselves. - exec rpc.statd --no-notify -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 2b7a167..e5b4c98 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -247,6 +247,7 @@ int main (int argc, char **argv) - int port = 0, out_port = 0; - int nlm_udp = 0, nlm_tcp = 0; - struct rlimit rlim; -+ int notify_sockfd; - - /* Default: daemon mode, no other options */ - run_mode = 0; -@@ -437,7 +438,7 @@ int main (int argc, char **argv) - } - - /* Make sure we have a privilege port for calling into the kernel */ -- if (statd_get_socket() < 0) -+ if ((notify_sockfd = statd_get_socket()) < 0) - exit(1); - - /* If sm-notify didn't take all the state files, load -@@ -484,7 +485,7 @@ int main (int argc, char **argv) - * Handle incoming requests: SM_NOTIFY socket requests, as - * well as callbacks from lockd. - */ -- my_svc_run(); /* I rolled my own, Olaf made it better... */ -+ my_svc_run(notify_sockfd); /* I rolled my own, Olaf made it better... */ - - /* Only get here when simulating a crash so we should probably - * start sm-notify running again. As we have already dropped -diff --git a/utils/statd/statd.h b/utils/statd/statd.h -index a1d8035..231ac7e 100644 ---- a/utils/statd/statd.h -+++ b/utils/statd/statd.h -@@ -28,7 +28,7 @@ extern _Bool statd_present_address(const struct sockaddr *sap, char *buf, - __attribute__((__malloc__)) - extern char * statd_canonical_name(const char *hostname); - --extern void my_svc_run(void); -+extern void my_svc_run(int); - extern void notify_hosts(void); - extern void shuffle_dirs(void); - extern int statd_get_socket(void); -diff --git a/utils/statd/svc_run.c b/utils/statd/svc_run.c -index d98ecee..28c1ad6 100644 ---- a/utils/statd/svc_run.c -+++ b/utils/statd/svc_run.c -@@ -78,7 +78,7 @@ my_svc_exit(void) - * The heart of the server. A crib from libc for the most part... - */ - void --my_svc_run(void) -+my_svc_run(int sockfd) - { - FD_SET_TYPE readfds; - int selret; -@@ -96,6 +96,8 @@ my_svc_run(void) - } - - readfds = SVC_FDSET; -+ /* Set notify sockfd for waiting for reply */ -+ FD_SET(sockfd, &readfds); - if (notify) { - struct timeval tv; - -@@ -125,8 +127,10 @@ my_svc_run(void) - - default: - selret -= process_reply(&readfds); -- if (selret) -+ if (selret) { -+ FD_CLR(sockfd, &readfds); - svc_getreqset(&readfds); -+ } - } - } - } diff --git a/nfs-utils-1.3.5-rc2.patch b/nfs-utils-1.3.5-rc2.patch deleted file mode 100644 index df1bcae..0000000 --- a/nfs-utils-1.3.5-rc2.patch +++ /dev/null @@ -1,583 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 5164637..126d12c 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -69,6 +69,9 @@ tests/nsm_client/nlm_sm_inter_clnt.c - tests/nsm_client/nlm_sm_inter_svc.c - tests/nsm_client/nlm_sm_inter_xdr.c - utils/nfsidmap/nfsidmap -+systemd/nfs-server-generator -+systemd/nfs-config.service -+systemd/rpc-gssd.service - # cscope database files - cscope.* - # generic editor backup et al -diff --git a/configure.ac b/configure.ac -index 1daf5b8..d60f3a2 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -511,8 +511,20 @@ 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]) -+AC_CONFIG_COMMANDS_PRE([eval eval _sysconfdir=$sysconfdir]) -+ - AC_CONFIG_FILES([ - Makefile -+ systemd/nfs-config.service -+ systemd/rpc-gssd.service - linux-nfs/Makefile - support/Makefile - support/export/Makefile -diff --git a/support/export/export.c b/support/export/export.c -index e1bebce..0b8a858 100644 ---- a/support/export/export.c -+++ b/support/export/export.c -@@ -15,6 +15,8 @@ - #include - #include - #include -+#include -+#include - #include "xmalloc.h" - #include "nfslib.h" - #include "exportfs.h" -@@ -96,6 +98,69 @@ export_read(char *fname) - } - - /** -+ * export_d_read - read entries from /etc/exports. -+ * @fname: name of directory to read from -+ * -+ * Returns number of read entries. -+ * Based on mnt_table_parse_dir() in -+ * util-linux-ng/shlibs/mount/src/tab_parse.c -+ */ -+int -+export_d_read(const char *dname) -+{ -+ int n = 0, i; -+ struct dirent **namelist = NULL; -+ int volumes = 0; -+ -+ -+ n = scandir(dname, &namelist, NULL, versionsort); -+ if (n < 0) { -+ if (errno == ENOENT) -+ /* Silently return */ -+ return volumes; -+ xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); -+ } else if (n == 0) -+ return volumes; -+ -+ for (i = 0; i < n; i++) { -+ struct dirent *d = namelist[i]; -+ size_t namesz; -+ char fname[PATH_MAX + 1]; -+ int fname_len; -+ -+ -+ if (d->d_type != DT_UNKNOWN -+ && d->d_type != DT_REG -+ && d->d_type != DT_LNK) -+ continue; -+ if (*d->d_name == '.') -+ continue; -+ -+#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) -+ namesz = strlen(d->d_name); -+ if (!namesz -+ || namesz < _EXT_EXPORT_SIZ + 1 -+ || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), -+ _EXT_EXPORT)) -+ continue; -+ -+ fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); -+ if (fname_len > PATH_MAX) { -+ xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); -+ continue; -+ } -+ -+ volumes += export_read(fname); -+ } -+ -+ for (i = 0; i < n; i++) -+ free(namelist[i]); -+ free(namelist); -+ -+ return volumes; -+} -+ -+/** - * export_create - create an in-core nfs_export record from an export entry - * @xep: export entry to lookup - * @canonical: if set, e_hostname is known to be canonical DNS name -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 4cac203..f033329 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -135,6 +135,7 @@ int client_member(const char *client, - const char *name); - - int export_read(char *fname); -+int export_d_read(const char *dname); - void export_reset(nfs_export *); - nfs_export * export_lookup(char *hname, char *path, int caconical); - nfs_export * export_find(const struct addrinfo *ai, -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -index 03f96e9..49c9b8d 100644 ---- a/systemd/Makefile.am -+++ b/systemd/Makefile.am -@@ -39,8 +39,16 @@ endif - EXTRA_DIST = $(unit_files) - - unit_dir = /usr/lib/systemd/system -+generator_dir = /usr/lib/systemd/system-generators -+ -+EXTRA_PROGRAMS = nfs-server-generator -+genexecdir = $(generator_dir) -+nfs_server_generator_LDADD = ../support/export/libexport.a \ -+ ../support/nfs/libnfs.a \ -+ ../support/misc/libmisc.a - - if INSTALL_SYSTEMD -+genexec_PROGRAMS = nfs-server-generator - install-data-hook: $(unit_files) - mkdir -p $(DESTDIR)/$(unitdir) - cp $(unit_files) $(DESTDIR)/$(unitdir) -diff --git a/systemd/nfs-config.service b/systemd/nfs-config.service -deleted file mode 100644 -index bd69e84..0000000 ---- a/systemd/nfs-config.service -+++ /dev/null -@@ -1,13 +0,0 @@ --[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=/usr/libexec/nfs-utils/nfs-utils_env.sh -diff --git a/systemd/nfs-config.service.in b/systemd/nfs-config.service.in -new file mode 100644 -index 0000000..e89dc54 ---- /dev/null -+++ b/systemd/nfs-config.service.in -@@ -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 --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c -new file mode 100644 -index 0000000..f47718e ---- /dev/null -+++ b/systemd/nfs-server-generator.c -@@ -0,0 +1,150 @@ -+/* -+ * nfs-server-generator: -+ * systemd generator to create ordering dependencies between -+ * nfs-server and various filesystem mounts -+ * -+ * 1/ nfs-server should start Before any 'nfs' mountpoints are -+ * mounted, in case they are loop-back mounts. This ordering is particularly -+ * important for the shutdown side, so the nfs-server is stopped -+ * after the filesystems are unmounted. -+ * 2/ nfs-server should start After all exported filesystems are mounted -+ * so there is no risk of exporting the underlying directory. -+ * This is particularly important for _net mounts which -+ * are not caught by "local-fs.target". -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "misc.h" -+#include "nfslib.h" -+#include "exportfs.h" -+ -+/* A simple "set of strings" to remove duplicates -+ * found in /etc/exports -+ */ -+struct list { -+ struct list *next; -+ char *name; -+}; -+static int is_unique(struct list **lp, char *path) -+{ -+ struct list *l = *lp; -+ -+ while (l) { -+ if (strcmp(l->name, path) == 0) -+ return 0; -+ l = l->next; -+ } -+ l = malloc(sizeof(*l)); -+ if (l == NULL) -+ return 0; -+ l->name = path; -+ l->next = *lp; -+ *lp = l; -+ return 1; -+} -+ -+/* We need to convert a path name to a systemd unit -+ * name. This requires some translation ('/' -> '-') -+ * and some escaping. -+ */ -+static void systemd_escape(FILE *f, char *path) -+{ -+ while (*path == '/') -+ path++; -+ if (!*path) { -+ /* "/" becomes "-", otherwise leading "/" is ignored */ -+ fputs("-", f); -+ return; -+ } -+ while (*path) { -+ char c = *path++; -+ -+ if (c == '/') { -+ /* multiple non-trailing slashes become '-' */ -+ while (*path == '/') -+ path++; -+ if (*path) -+ fputs("-", f); -+ } else if (isalnum(c) || c == ':' || c == '.') -+ fputc(c, f); -+ else -+ fprintf(f, "\\x%02x", c & 0xff); -+ } -+} -+ -+int main(int argc, char *argv[]) -+{ -+ char *path; -+ char dirbase[] = "/nfs-server.service.d"; -+ char filebase[] = "/order-with-mounts.conf"; -+ nfs_export *exp; -+ int i; -+ struct list *list = NULL; -+ FILE *f, *fstab; -+ struct mntent *mnt; -+ -+ if (argc != 4 || argv[1][0] != '/') { -+ fprintf(stderr, "nfs-server-generator: create systemd dependencies for nfs-server\n"); -+ fprintf(stderr, "Usage: normal-dir early-dir late-dir\n"); -+ exit(1); -+ } -+ -+ path = malloc(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase)); -+ if (!path) -+ exit(2); -+ if (export_read(_PATH_EXPORTS) + -+ export_d_read(_PATH_EXPORTS_D) == 0) -+ /* Nothing is exported, so nothing to do */ -+ exit(0); -+ -+ strcat(strcpy(path, argv[1]), dirbase); -+ mkdir(path, 0755); -+ strcat(path, filebase); -+ f = fopen(path, "w"); -+ if (!f) -+ exit(1); -+ fprintf(f, "# Automatically generated by nfs-server-generator\n\n[Unit]\n"); -+ -+ for (i = 0; i < MCL_MAXTYPES; i++) { -+ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { -+ if (!is_unique(&list, exp->m_export.e_path)) -+ continue; -+ if (strchr(exp->m_export.e_path, ' ')) -+ fprintf(f, "RequiresMountsFor=\"%s\"\n", -+ exp->m_export.e_path); -+ else -+ fprintf(f, "RequiresMountsFor=%s\n", -+ exp->m_export.e_path); -+ } -+ } -+ -+ fstab = setmntent("/etc/fstab", "r"); -+ if (!fstab) -+ exit(1); -+ -+ while ((mnt = getmntent(fstab)) != NULL) { -+ if (strcmp(mnt->mnt_type, "nfs") != 0 && -+ strcmp(mnt->mnt_type, "nfs4") != 0) -+ continue; -+ fprintf(f, "Before= "); -+ systemd_escape(f, mnt->mnt_dir); -+ fprintf(f, ".mount\n"); -+ } -+ -+ fclose(fstab); -+ fclose(f); -+ -+ exit(0); -+} -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 2ccdc63..196c818 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -16,9 +16,6 @@ Before= rpc-statd-notify.service - Wants=auth-rpcgss-module.service - After=rpc-gssd.service gssproxy.service rpc-svcgssd.service - --# start/stop server before/after client --Before=remote-fs-pre.target -- - Wants=nfs-config.service - After=nfs-config.service - -diff --git a/systemd/rpc-gssd.service b/systemd/rpc-gssd.service -deleted file mode 100644 -index d4a3819..0000000 ---- a/systemd/rpc-gssd.service -+++ /dev/null -@@ -1,19 +0,0 @@ --[Unit] --Description=RPC security service for NFS client and server --DefaultDependencies=no --Conflicts=umount.target --Requires=var-lib-nfs-rpc_pipefs.mount --After=var-lib-nfs-rpc_pipefs.mount -- --ConditionPathExists=/etc/krb5.keytab -- --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 $GSSDARGS -diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in -new file mode 100644 -index 0000000..1a7911c ---- /dev/null -+++ b/systemd/rpc-gssd.service.in -@@ -0,0 +1,19 @@ -+[Unit] -+Description=RPC security service for NFS client and server -+DefaultDependencies=no -+Conflicts=umount.target -+Requires=var-lib-nfs-rpc_pipefs.mount -+After=var-lib-nfs-rpc_pipefs.mount -+ -+ConditionPathExists=@_sysconfdir@/krb5.keytab -+ -+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 $GSSDARGS -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index a00b5ea..4ac2c15 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -26,7 +26,6 @@ - #include - #include - #include --#include - #include - #include - -@@ -47,7 +46,6 @@ static void error(nfs_export *exp, int err); - static void usage(const char *progname, int n); - static void validate_export(nfs_export *exp); - static int matchhostname(const char *hostname1, const char *hostname2); --static int export_d_read(const char *dname); - static void grab_lockfile(void); - static void release_lockfile(void); - -@@ -700,63 +698,6 @@ out: - return result; - } - --/* Based on mnt_table_parse_dir() in -- util-linux-ng/shlibs/mount/src/tab_parse.c */ --static int --export_d_read(const char *dname) --{ -- int n = 0, i; -- struct dirent **namelist = NULL; -- int volumes = 0; -- -- -- n = scandir(dname, &namelist, NULL, versionsort); -- if (n < 0) { -- if (errno == ENOENT) -- /* Silently return */ -- return volumes; -- xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); -- } else if (n == 0) -- return volumes; -- -- for (i = 0; i < n; i++) { -- struct dirent *d = namelist[i]; -- size_t namesz; -- char fname[PATH_MAX + 1]; -- int fname_len; -- -- -- if (d->d_type != DT_UNKNOWN -- && d->d_type != DT_REG -- && d->d_type != DT_LNK) -- continue; -- if (*d->d_name == '.') -- continue; -- --#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) -- namesz = strlen(d->d_name); -- if (!namesz -- || namesz < _EXT_EXPORT_SIZ + 1 -- || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), -- _EXT_EXPORT)) -- continue; -- -- fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); -- if (fname_len > PATH_MAX) { -- xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); -- continue; -- } -- -- volumes += export_read(fname); -- } -- -- for (i = 0; i < n; i++) -- free(namelist[i]); -- free(namelist); -- -- return volumes; --} -- - static char - dumpopt(char c, char *fmt, ...) - { -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index b9200c7..d4ab894 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -23,6 +23,29 @@ is the NFSv4 ID <-> name mapping daemon. It provides functionality to - the NFSv4 kernel client and server, to which it communicates via - upcalls, by translating user and group IDs to names, and vice versa. - .Pp -+The system derives the -+.I user -+part of the string by performing a password or group lookup. -+The lookup mechanism is configured in -+.Pa /etc/idmapd.conf -+.Pp -+By default, the -+.I domain -+part of the string is the system's DNS domain name. -+It can also be specified in -+.Pa /etc/idmapd.conf -+if the system is multi-homed, -+or if the system's DNS domain name does -+not match the name of the system's Kerberos realm. -+.Pp -+When the domain is not specified in /etc/idmapd.conf -+the local DNS server will be queried for the -+.Sy _nfsv4idmapdomain -+text record. If the record exists -+that will be used as the domain. When the record -+does not exist, the domain part of the DNS domain -+will used. -+.Pp - Note that on more recent kernels only the NFSv4 server uses - .Nm . - The NFSv4 client instead uses -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 9de6794..d5dfb5e 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -948,6 +948,7 @@ static int nfs_is_permanent_error(int error) - case ETIMEDOUT: - case ECONNREFUSED: - case EHOSTUNREACH: -+ case EOPNOTSUPP: /* aka RPC_PROGNOTREGISTERED */ - case EAGAIN: - return 0; /* temporary */ - default: -@@ -1019,8 +1020,7 @@ static int nfsmount_parent(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -- /* retry background mounts when the server is not up */ -- if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) { -+ if (nfs_is_permanent_error(errno)) { - mount_error(mi->spec, mi->node, errno); - return EX_FAIL; - } -@@ -1055,8 +1055,7 @@ static int nfsmount_child(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -- /* retry background mounts when the server is not up */ -- if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) -+ if (nfs_is_permanent_error(errno)) - break; - - if (time(NULL) > timeout) -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 2f17cf2..2af16f3 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -39,6 +39,15 @@ if the system is multi-homed, - or if the system's DNS domain name does - not match the name of the system's Kerberos realm. - .PP -+When the domain is not specified in -+.I /etc/idmapd.conf -+the local DNS server will be queried for the -+.I _nfsv4idmapdomain -+text record. If the record exists -+that will be used as the domain. When the record -+does not exist, the domain part of the DNS domain -+will used. -+.PP - The - .I /usr/sbin/nfsidmap - program performs translations on behalf of the kernel. diff --git a/nfs-utils-1.3.5-rc3.patch b/nfs-utils-1.3.5-rc3.patch deleted file mode 100644 index 54d8ee2..0000000 --- a/nfs-utils-1.3.5-rc3.patch +++ /dev/null @@ -1,929 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 5164637..126d12c 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -69,6 +69,9 @@ tests/nsm_client/nlm_sm_inter_clnt.c - tests/nsm_client/nlm_sm_inter_svc.c - tests/nsm_client/nlm_sm_inter_xdr.c - utils/nfsidmap/nfsidmap -+systemd/nfs-server-generator -+systemd/nfs-config.service -+systemd/rpc-gssd.service - # cscope database files - cscope.* - # generic editor backup et al -diff --git a/Makefile.am b/Makefile.am -index 4a2edc6..e1f39aa 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -23,7 +23,6 @@ ACLOCAL_AMFLAGS = -I aclocal - - install-data-hook: - if [ ! -d $(DESTDIR)$(statedir) ]; then mkdir -p $(DESTDIR)$(statedir); fi -- touch $(DESTDIR)$(statedir)/xtab; chmod 644 $(DESTDIR)$(statedir)/xtab - touch $(DESTDIR)$(statedir)/etab; chmod 644 $(DESTDIR)$(statedir)/etab - touch $(DESTDIR)$(statedir)/rmtab; chmod 644 $(DESTDIR)$(statedir)/rmtab - mkdir -p $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak -@@ -32,7 +31,7 @@ install-data-hook: - -chown $(statduser) $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak $(DESTDIR)$(statdpath)/state - - uninstall-hook: -- rm $(DESTDIR)$(statedir)/xtab -+ rm -f $(DESTDIR)$(statedir)/xtab - rm $(DESTDIR)$(statedir)/etab - rm $(DESTDIR)$(statedir)/rmtab - rm $(DESTDIR)$(statdpath)/state -diff --git a/configure.ac b/configure.ac -index 1daf5b8..8a5aa2e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -24,6 +24,12 @@ AC_ARG_WITH(statedir, - statedir=$withval, - statedir=/var/lib/nfs) - AC_SUBST(statedir) -+AC_ARG_WITH(nfsconfig, -+ [AC_HELP_STRING([--with-nfsconfig=/config/file], -+ [use general config file /config/file @<:@default=/etc/nfs.conf@:>@])], -+ nfsconfig=$withval, -+ nfsconfig=/etc/nfs.conf) -+ AC_SUBST(nfsconfig) - AC_ARG_WITH(statdpath, - [AC_HELP_STRING([--with-statdpath=/foo], - [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])], -@@ -468,6 +474,7 @@ dnl Export some path names to config.h - dnl ************************************************************* - AC_DEFINE_UNQUOTED(NFS_STATEDIR, "$statedir", [This defines the location of the NFS state files. Warning: this must match definitions in config.mk!]) - AC_DEFINE_UNQUOTED(NSM_DEFAULT_STATEDIR, "$statdpath", [Define this to the pathname where statd keeps its state file]) -+AC_DEFINE_UNQUOTED(NFS_CONFFILE, "$nfsconfig", [This defines the location of NFS daemon config file]) - - if test "x$cross_compiling" = "xno"; then - CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD-"$CFLAGS"} -@@ -511,8 +518,20 @@ 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]) -+AC_CONFIG_COMMANDS_PRE([eval eval _sysconfdir=$sysconfdir]) -+ - AC_CONFIG_FILES([ - Makefile -+ systemd/nfs-config.service -+ systemd/rpc-gssd.service - linux-nfs/Makefile - support/Makefile - support/export/Makefile -diff --git a/support/export/export.c b/support/export/export.c -index e1bebce..15e91cb 100644 ---- a/support/export/export.c -+++ b/support/export/export.c -@@ -15,6 +15,8 @@ - #include - #include - #include -+#include -+#include - #include "xmalloc.h" - #include "nfslib.h" - #include "exportfs.h" -@@ -68,11 +70,15 @@ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep) - /** - * export_read - read entries from /etc/exports - * @fname: name of file to read from -+ * @ignore_hosts: don't check validity of host names - * - * Returns number of read entries. -+ * @ignore_hosts can be set when the host names won't be used -+ * and when getting delays or errors due to problems with -+ * hostname looking is not acceptable. - */ - int --export_read(char *fname) -+export_read(char *fname, int ignore_hosts) - { - struct exportent *eep; - nfs_export *exp; -@@ -81,7 +87,7 @@ export_read(char *fname) - - setexportent(fname, "r"); - while ((eep = getexportent(0,1)) != NULL) { -- exp = export_lookup(eep->e_hostname, eep->e_path, 0); -+ exp = export_lookup(eep->e_hostname, eep->e_path, ignore_hosts); - if (!exp) { - if (export_create(eep, 0)) - /* possible complaints already logged */ -@@ -96,6 +102,70 @@ export_read(char *fname) - } - - /** -+ * export_d_read - read entries from /etc/exports. -+ * @fname: name of directory to read from -+ * @ignore_hosts: don't check validity of host names -+ * -+ * Returns number of read entries. -+ * Based on mnt_table_parse_dir() in -+ * util-linux-ng/shlibs/mount/src/tab_parse.c -+ */ -+int -+export_d_read(const char *dname, int ignore_hosts) -+{ -+ int n = 0, i; -+ struct dirent **namelist = NULL; -+ int volumes = 0; -+ -+ -+ n = scandir(dname, &namelist, NULL, versionsort); -+ if (n < 0) { -+ if (errno == ENOENT) -+ /* Silently return */ -+ return volumes; -+ xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); -+ } else if (n == 0) -+ return volumes; -+ -+ for (i = 0; i < n; i++) { -+ struct dirent *d = namelist[i]; -+ size_t namesz; -+ char fname[PATH_MAX + 1]; -+ int fname_len; -+ -+ -+ if (d->d_type != DT_UNKNOWN -+ && d->d_type != DT_REG -+ && d->d_type != DT_LNK) -+ continue; -+ if (*d->d_name == '.') -+ continue; -+ -+#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) -+ namesz = strlen(d->d_name); -+ if (!namesz -+ || namesz < _EXT_EXPORT_SIZ + 1 -+ || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), -+ _EXT_EXPORT)) -+ continue; -+ -+ fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); -+ if (fname_len > PATH_MAX) { -+ xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); -+ continue; -+ } -+ -+ volumes += export_read(fname, ignore_hosts); -+ } -+ -+ for (i = 0; i < n; i++) -+ free(namelist[i]); -+ free(namelist); -+ -+ return volumes; -+} -+ -+/** - * export_create - create an in-core nfs_export record from an export entry - * @xep: export entry to lookup - * @canonical: if set, e_hostname is known to be canonical DNS name -diff --git a/support/export/xtab.c b/support/export/xtab.c -index e953071..10d9dbc 100644 ---- a/support/export/xtab.c -+++ b/support/export/xtab.c -@@ -1,7 +1,7 @@ - /* - * support/export/xtab.c - * -- * Interface to the xtab file. -+ * Interface to the etab/exports file. - * - * Copyright (C) 1995, 1996 Olaf Kirch - */ -@@ -29,7 +29,6 @@ xtab_read(char *xtab, char *lockfn, int is_export) - { - /* is_export == 0 => reading /proc/fs/nfs/exports - we know these things are exported to kernel - * is_export == 1 => reading /var/lib/nfs/etab - these things are allowed to be exported -- * is_export == 2 => reading /var/lib/nfs/xtab - these things might be known to kernel - */ - struct exportent *xp; - nfs_export *exp; -@@ -55,9 +54,6 @@ xtab_read(char *xtab, char *lockfn, int is_export) - if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0) - v4root_needed = 0; - break; -- case 2: -- exp->m_exported = -1;/* may be exported */ -- break; - } - } - endexportent(); -@@ -79,7 +75,7 @@ xtab_mount_read(void) - return xtab_read(_PATH_PROC_EXPORTS_ALT, - _PATH_PROC_EXPORTS_ALT, 0); - } else -- return xtab_read(_PATH_XTAB, _PATH_XTABLCK, 2); -+ return 0; - } - - int -@@ -135,29 +131,6 @@ xtab_export_write() - return xtab_write(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1); - } - --int --xtab_mount_write() --{ -- return xtab_write(_PATH_XTAB, _PATH_XTABTMP, _PATH_XTABLCK, 0); --} -- --void --xtab_append(nfs_export *exp) --{ -- struct exportent xe; -- int lockid; -- -- if ((lockid = xflock(_PATH_XTABLCK, "w")) < 0) -- return; -- setexportent(_PATH_XTAB, "a"); -- xe = exp->m_export; -- xe.e_hostname = exp->m_client->m_hostname; -- putexportent(&xe); -- endexportent(); -- xfunlock(lockid); -- exp->m_xtabent = 1; --} -- - /* - * rename newfile onto oldfile unless - * they are identical -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 4cac203..08ef30a 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -96,7 +96,7 @@ typedef struct mexport { - struct mexport * m_next; - struct mclient * m_client; - struct exportent m_export; -- int m_exported; /* known to knfsd. -1 means not sure */ -+ int m_exported; /* known to knfsd. */ - int m_xtabent : 1, /* xtab entry exists */ - m_mayexport: 1, /* derived from xtabbed */ - m_changed : 1, /* options (may) have changed */ -@@ -134,7 +134,8 @@ struct addrinfo * client_resolve(const struct sockaddr *sap); - int client_member(const char *client, - const char *name); - --int export_read(char *fname); -+int export_read(char *fname, int ignore_hosts); -+int export_d_read(const char *dname, int ignore_hosts); - void export_reset(nfs_export *); - nfs_export * export_lookup(char *hname, char *path, int caconical); - nfs_export * export_find(const struct addrinfo *ai, -@@ -149,9 +150,7 @@ int export_unexport(nfs_export *); - - int xtab_mount_read(void); - int xtab_export_read(void); --int xtab_mount_write(void); - int xtab_export_write(void); --void xtab_append(nfs_export *); - - int secinfo_addflavor(struct flav_info *, struct exportent *); - -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index ddd71ac..777f398 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -35,15 +35,6 @@ - #ifndef _PATH_IDMAPDCONF - #define _PATH_IDMAPDCONF "/etc/idmapd.conf" - #endif --#ifndef _PATH_XTAB --#define _PATH_XTAB NFS_STATEDIR "/xtab" --#endif --#ifndef _PATH_XTABTMP --#define _PATH_XTABTMP NFS_STATEDIR "/xtab.tmp" --#endif --#ifndef _PATH_XTABLCK --#define _PATH_XTABLCK NFS_STATEDIR "/.xtab.lock" --#endif - #ifndef _PATH_ETAB - #define _PATH_ETAB NFS_STATEDIR "/etab" - #endif -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -index 03f96e9..49c9b8d 100644 ---- a/systemd/Makefile.am -+++ b/systemd/Makefile.am -@@ -39,8 +39,16 @@ endif - EXTRA_DIST = $(unit_files) - - unit_dir = /usr/lib/systemd/system -+generator_dir = /usr/lib/systemd/system-generators -+ -+EXTRA_PROGRAMS = nfs-server-generator -+genexecdir = $(generator_dir) -+nfs_server_generator_LDADD = ../support/export/libexport.a \ -+ ../support/nfs/libnfs.a \ -+ ../support/misc/libmisc.a - - if INSTALL_SYSTEMD -+genexec_PROGRAMS = nfs-server-generator - install-data-hook: $(unit_files) - mkdir -p $(DESTDIR)/$(unitdir) - cp $(unit_files) $(DESTDIR)/$(unitdir) -diff --git a/systemd/nfs-config.service b/systemd/nfs-config.service -deleted file mode 100644 -index bd69e84..0000000 ---- a/systemd/nfs-config.service -+++ /dev/null -@@ -1,13 +0,0 @@ --[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=/usr/libexec/nfs-utils/nfs-utils_env.sh -diff --git a/systemd/nfs-config.service.in b/systemd/nfs-config.service.in -new file mode 100644 -index 0000000..e89dc54 ---- /dev/null -+++ b/systemd/nfs-config.service.in -@@ -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 --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c -new file mode 100644 -index 0000000..7c40b3f ---- /dev/null -+++ b/systemd/nfs-server-generator.c -@@ -0,0 +1,150 @@ -+/* -+ * nfs-server-generator: -+ * systemd generator to create ordering dependencies between -+ * nfs-server and various filesystem mounts -+ * -+ * 1/ nfs-server should start Before any 'nfs' mountpoints are -+ * mounted, in case they are loop-back mounts. This ordering is particularly -+ * important for the shutdown side, so the nfs-server is stopped -+ * after the filesystems are unmounted. -+ * 2/ nfs-server should start After all exported filesystems are mounted -+ * so there is no risk of exporting the underlying directory. -+ * This is particularly important for _net mounts which -+ * are not caught by "local-fs.target". -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "misc.h" -+#include "nfslib.h" -+#include "exportfs.h" -+ -+/* A simple "set of strings" to remove duplicates -+ * found in /etc/exports -+ */ -+struct list { -+ struct list *next; -+ char *name; -+}; -+static int is_unique(struct list **lp, char *path) -+{ -+ struct list *l = *lp; -+ -+ while (l) { -+ if (strcmp(l->name, path) == 0) -+ return 0; -+ l = l->next; -+ } -+ l = malloc(sizeof(*l)); -+ if (l == NULL) -+ return 0; -+ l->name = path; -+ l->next = *lp; -+ *lp = l; -+ return 1; -+} -+ -+/* We need to convert a path name to a systemd unit -+ * name. This requires some translation ('/' -> '-') -+ * and some escaping. -+ */ -+static void systemd_escape(FILE *f, char *path) -+{ -+ while (*path == '/') -+ path++; -+ if (!*path) { -+ /* "/" becomes "-", otherwise leading "/" is ignored */ -+ fputs("-", f); -+ return; -+ } -+ while (*path) { -+ char c = *path++; -+ -+ if (c == '/') { -+ /* multiple non-trailing slashes become '-' */ -+ while (*path == '/') -+ path++; -+ if (*path) -+ fputs("-", f); -+ } else if (isalnum(c) || c == ':' || c == '.') -+ fputc(c, f); -+ else -+ fprintf(f, "\\x%02x", c & 0xff); -+ } -+} -+ -+int main(int argc, char *argv[]) -+{ -+ char *path; -+ char dirbase[] = "/nfs-server.service.d"; -+ char filebase[] = "/order-with-mounts.conf"; -+ nfs_export *exp; -+ int i; -+ struct list *list = NULL; -+ FILE *f, *fstab; -+ struct mntent *mnt; -+ -+ if (argc != 4 || argv[1][0] != '/') { -+ fprintf(stderr, "nfs-server-generator: create systemd dependencies for nfs-server\n"); -+ fprintf(stderr, "Usage: normal-dir early-dir late-dir\n"); -+ exit(1); -+ } -+ -+ path = malloc(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase)); -+ if (!path) -+ exit(2); -+ if (export_read(_PATH_EXPORTS, 1) + -+ export_d_read(_PATH_EXPORTS_D, 1) == 0) -+ /* Nothing is exported, so nothing to do */ -+ exit(0); -+ -+ strcat(strcpy(path, argv[1]), dirbase); -+ mkdir(path, 0755); -+ strcat(path, filebase); -+ f = fopen(path, "w"); -+ if (!f) -+ exit(1); -+ fprintf(f, "# Automatically generated by nfs-server-generator\n\n[Unit]\n"); -+ -+ for (i = 0; i < MCL_MAXTYPES; i++) { -+ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { -+ if (!is_unique(&list, exp->m_export.e_path)) -+ continue; -+ if (strchr(exp->m_export.e_path, ' ')) -+ fprintf(f, "RequiresMountsFor=\"%s\"\n", -+ exp->m_export.e_path); -+ else -+ fprintf(f, "RequiresMountsFor=%s\n", -+ exp->m_export.e_path); -+ } -+ } -+ -+ fstab = setmntent("/etc/fstab", "r"); -+ if (!fstab) -+ exit(1); -+ -+ while ((mnt = getmntent(fstab)) != NULL) { -+ if (strcmp(mnt->mnt_type, "nfs") != 0 && -+ strcmp(mnt->mnt_type, "nfs4") != 0) -+ continue; -+ fprintf(f, "Before= "); -+ systemd_escape(f, mnt->mnt_dir); -+ fprintf(f, ".mount\n"); -+ } -+ -+ fclose(fstab); -+ fclose(f); -+ -+ exit(0); -+} -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 2ccdc63..196c818 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -16,9 +16,6 @@ Before= rpc-statd-notify.service - Wants=auth-rpcgss-module.service - After=rpc-gssd.service gssproxy.service rpc-svcgssd.service - --# start/stop server before/after client --Before=remote-fs-pre.target -- - Wants=nfs-config.service - After=nfs-config.service - -diff --git a/systemd/rpc-gssd.service b/systemd/rpc-gssd.service -deleted file mode 100644 -index d4a3819..0000000 ---- a/systemd/rpc-gssd.service -+++ /dev/null -@@ -1,19 +0,0 @@ --[Unit] --Description=RPC security service for NFS client and server --DefaultDependencies=no --Conflicts=umount.target --Requires=var-lib-nfs-rpc_pipefs.mount --After=var-lib-nfs-rpc_pipefs.mount -- --ConditionPathExists=/etc/krb5.keytab -- --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 $GSSDARGS -diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in -new file mode 100644 -index 0000000..1a7911c ---- /dev/null -+++ b/systemd/rpc-gssd.service.in -@@ -0,0 +1,19 @@ -+[Unit] -+Description=RPC security service for NFS client and server -+DefaultDependencies=no -+Conflicts=umount.target -+Requires=var-lib-nfs-rpc_pipefs.mount -+After=var-lib-nfs-rpc_pipefs.mount -+ -+ConditionPathExists=@_sysconfdir@/krb5.keytab -+ -+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 $GSSDARGS -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 4ca4bc4..88ccdae 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -412,6 +412,8 @@ class DeviceData: - print(' short reads: %d short writes: %d' % \ - (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])) - print(' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']) -+ print(' pNFS READs: %d' % self.__nfs_data['pnfsreads']) -+ print(' pNFS WRITEs: %d' % self.__nfs_data['pnfswrites']) - - def display_nfs_bytes(self): - """Pretty-print the NFS event counters -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index a00b5ea..98368a5 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -26,7 +26,6 @@ - #include - #include - #include --#include - #include - #include - -@@ -47,7 +46,6 @@ static void error(nfs_export *exp, int err); - static void usage(const char *progname, int n); - static void validate_export(nfs_export *exp); - static int matchhostname(const char *hostname1, const char *hostname2); --static int export_d_read(const char *dname); - static void grab_lockfile(void); - static void release_lockfile(void); - -@@ -185,8 +183,8 @@ main(int argc, char **argv) - atexit(release_lockfile); - - if (f_export && ! f_ignore) { -- if (! (export_read(_PATH_EXPORTS) + -- export_d_read(_PATH_EXPORTS_D))) { -+ if (! (export_read(_PATH_EXPORTS, 0) + -+ export_d_read(_PATH_EXPORTS_D, 0))) { - if (f_verbose) - xlog(L_WARNING, "No file systems exported!"); - } -@@ -221,8 +219,6 @@ main(int argc, char **argv) - xtab_export_write(); - if (new_cache) - cache_flush(force_flush); -- if (!new_cache) -- xtab_mount_write(); - - return export_errno; - } -@@ -240,7 +236,7 @@ exports_update_one(nfs_export *exp, int verbose) - exp->m_export.e_path, exp->m_export.e_mountpoint); - exp->m_mayexport = 0; - } -- if (exp->m_mayexport && ((exp->m_exported<1) || exp->m_changed)) { -+ if (exp->m_mayexport && exp->m_changed) { - if (verbose) - printf("%sexporting %s:%s to kernel\n", - exp->m_exported ?"re":"", -@@ -700,63 +696,6 @@ out: - return result; - } - --/* Based on mnt_table_parse_dir() in -- util-linux-ng/shlibs/mount/src/tab_parse.c */ --static int --export_d_read(const char *dname) --{ -- int n = 0, i; -- struct dirent **namelist = NULL; -- int volumes = 0; -- -- -- n = scandir(dname, &namelist, NULL, versionsort); -- if (n < 0) { -- if (errno == ENOENT) -- /* Silently return */ -- return volumes; -- xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); -- } else if (n == 0) -- return volumes; -- -- for (i = 0; i < n; i++) { -- struct dirent *d = namelist[i]; -- size_t namesz; -- char fname[PATH_MAX + 1]; -- int fname_len; -- -- -- if (d->d_type != DT_UNKNOWN -- && d->d_type != DT_REG -- && d->d_type != DT_LNK) -- continue; -- if (*d->d_name == '.') -- continue; -- --#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) -- namesz = strlen(d->d_name); -- if (!namesz -- || namesz < _EXT_EXPORT_SIZ + 1 -- || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), -- _EXT_EXPORT)) -- continue; -- -- fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); -- if (fname_len > PATH_MAX) { -- xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); -- continue; -- } -- -- volumes += export_read(fname); -- } -- -- for (i = 0; i < n; i++) -- free(namelist[i]); -- free(namelist); -- -- return volumes; --} -- - static char - dumpopt(char c, char *fmt, ...) - { -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index b9200c7..d4ab894 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -23,6 +23,29 @@ is the NFSv4 ID <-> name mapping daemon. It provides functionality to - the NFSv4 kernel client and server, to which it communicates via - upcalls, by translating user and group IDs to names, and vice versa. - .Pp -+The system derives the -+.I user -+part of the string by performing a password or group lookup. -+The lookup mechanism is configured in -+.Pa /etc/idmapd.conf -+.Pp -+By default, the -+.I domain -+part of the string is the system's DNS domain name. -+It can also be specified in -+.Pa /etc/idmapd.conf -+if the system is multi-homed, -+or if the system's DNS domain name does -+not match the name of the system's Kerberos realm. -+.Pp -+When the domain is not specified in /etc/idmapd.conf -+the local DNS server will be queried for the -+.Sy _nfsv4idmapdomain -+text record. If the record exists -+that will be used as the domain. When the record -+does not exist, the domain part of the DNS domain -+will used. -+.Pp - Note that on more recent kernels only the NFSv4 server uses - .Nm . - The NFSv4 client instead uses -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 9de6794..d5dfb5e 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -948,6 +948,7 @@ static int nfs_is_permanent_error(int error) - case ETIMEDOUT: - case ECONNREFUSED: - case EHOSTUNREACH: -+ case EOPNOTSUPP: /* aka RPC_PROGNOTREGISTERED */ - case EAGAIN: - return 0; /* temporary */ - default: -@@ -1019,8 +1020,7 @@ static int nfsmount_parent(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -- /* retry background mounts when the server is not up */ -- if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) { -+ if (nfs_is_permanent_error(errno)) { - mount_error(mi->spec, mi->node, errno); - return EX_FAIL; - } -@@ -1055,8 +1055,7 @@ static int nfsmount_child(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -- /* retry background mounts when the server is not up */ -- if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) -+ if (nfs_is_permanent_error(errno)) - break; - - if (time(NULL) > timeout) -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index 0881d9a..b612d88 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -46,7 +46,6 @@ void - auth_init(void) - { - auth_reload(); -- xtab_mount_write(); - } - - /* -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 7a51b09..981abd4 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -107,7 +107,6 @@ unregister_services (void) - static void - cleanup_lockfiles (void) - { -- unlink(_PATH_XTABLCK); - unlink(_PATH_ETABLCK); - unlink(_PATH_RMTABLCK); - } -@@ -289,7 +288,7 @@ mount_umntall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), - xlog(D_CALL, "Received UMNTALL request from %s", - host_ntop(sap, buf, sizeof(buf))); - -- /* Reload /etc/xtab if necessary */ -+ /* Reload /etc/exports if necessary */ - auth_reload(); - - mountlist_del_all(nfs_getrpccaller(rqstp->rq_xprt)); -@@ -350,7 +349,7 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) - if (*p == '\0') - p = "/"; - -- /* Reload /etc/xtab if necessary */ -+ /* Reload /etc/exports if necessary */ - auth_reload(); - - /* Resolve symlinks */ -@@ -531,12 +530,6 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, - } else { - int did_export = 0; - retry: -- if (exp->m_exported<1) { -- export_export(exp); -- did_export = 1; -- } -- if (!exp->m_xtabent) -- xtab_append(exp); - - if (v3) - fh = getfh_size((struct sockaddr_in *)sap, p, 64); -diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c -index fcdda7f..e6e514b 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.c -+++ b/utils/nfsdcltrack/nfsdcltrack.c -@@ -43,6 +43,7 @@ - #include - #endif - -+#include "conffile.h" - #include "xlog.h" - #include "sqlite.h" - -@@ -55,6 +56,8 @@ - /* defined by RFC 3530 */ - #define NFS4_OPAQUE_LIMIT 1024 - -+char *conf_path = NFS_CONFFILE; -+ - /* private data structures */ - struct cltrack_cmd { - char *name; -@@ -553,6 +556,7 @@ int - main(int argc, char **argv) - { - char arg; -+ char *val; - int rc = 0; - char *progname, *cmdarg = NULL; - struct cltrack_cmd *cmd; -@@ -562,6 +566,14 @@ main(int argc, char **argv) - xlog_syslog(1); - xlog_stderr(0); - -+ conf_init(); -+ val = conf_get_str("nfsdcltrack", "storagedir"); -+ if (val) -+ storagedir = val; -+ rc = conf_get_num("nfsdcltrack", "debug", 0); -+ if (rc > 0) -+ xlog_config(D_ALL, 1); -+ - /* process command-line options */ - while ((arg = getopt_long(argc, argv, "hdfs:", longopts, - NULL)) != EOF) { -diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man -index 4b8f4d7..cc24b7a 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.man -+++ b/utils/nfsdcltrack/nfsdcltrack.man -@@ -67,6 +67,20 @@ Check to see if a nfs_client_id4 is allowed to reclaim. This command requires a - .IP "\fBgracedone\fR" 4 - .IX Item "gracedone" - Remove any unreclaimed client records from the database. This command requires a epoch boot time as an argument. -+.SH "EXTERNAL CONFIGURATION" -+The directory for stable storage information can be set via the file -+.B /etc/nfs.conf -+by setting the -+.B storagedir -+value in the -+.B nfsdcltrack -+section. For example: -+.in +5 -+[nfsdcltrack] -+.br -+ storagedir = /shared/nfs/nfsdcltrack -+.in -5 -+Debuging to syslog can also be enabled by setting "debug = 1" in this file. - .SH "LEGACY TRANSITION MECHANISM" - .IX Header "LEGACY TRANSITION MECHANISM" - The Linux kernel NFSv4 server has historically tracked this information -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 2f17cf2..2af16f3 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -39,6 +39,15 @@ if the system is multi-homed, - or if the system's DNS domain name does - not match the name of the system's Kerberos realm. - .PP -+When the domain is not specified in -+.I /etc/idmapd.conf -+the local DNS server will be queried for the -+.I _nfsv4idmapdomain -+text record. If the record exists -+that will be used as the domain. When the record -+does not exist, the domain part of the DNS domain -+will used. -+.PP - The - .I /usr/sbin/nfsidmap - program performs translations on behalf of the kernel. diff --git a/nfs-utils-2.1.1-nfs-config.patch b/nfs-utils-2.1.1-nfs-config.patch new file mode 100644 index 0000000..18f67a8 --- /dev/null +++ b/nfs-utils-2.1.1-nfs-config.patch @@ -0,0 +1,202 @@ +diff -up nfs-utils-2.1.1/configure.ac.orig nfs-utils-2.1.1/configure.ac +--- nfs-utils-2.1.1/configure.ac.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/configure.ac 2017-01-16 14:24:01.691124185 -0500 +@@ -518,6 +518,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]) +@@ -525,6 +530,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.1.1/systemd/Makefile.am.orig nfs-utils-2.1.1/systemd/Makefile.am +--- nfs-utils-2.1.1/systemd/Makefile.am.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/Makefile.am 2017-01-16 14:24:01.691124185 -0500 +@@ -5,6 +5,7 @@ MAINTAINERCLEANFILES = Makefile.in + unit_files = \ + nfs-client.target \ + \ ++ nfs-config.service \ + nfs-mountd.service \ + nfs-server.service \ + nfs-utils.service \ +diff -up nfs-utils-2.1.1/systemd/nfs-blkmap.service.orig nfs-utils-2.1.1/systemd/nfs-blkmap.service +--- nfs-utils-2.1.1/systemd/nfs-blkmap.service.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/nfs-blkmap.service 2017-01-16 14:24:01.691124185 -0500 +@@ -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.1.1/systemd/nfs-config.service.in.orig nfs-utils-2.1.1/systemd/nfs-config.service.in +--- nfs-utils-2.1.1/systemd/nfs-config.service.in.orig 2017-01-16 14:24:01.691124185 -0500 ++++ nfs-utils-2.1.1/systemd/nfs-config.service.in 2017-01-16 14:24:01.691124185 -0500 +@@ -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.1.1/systemd/nfs-idmapd.service.orig nfs-utils-2.1.1/systemd/nfs-idmapd.service +--- nfs-utils-2.1.1/systemd/nfs-idmapd.service.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/nfs-idmapd.service 2017-01-16 14:24:01.691124185 -0500 +@@ -6,6 +6,10 @@ After=var-lib-nfs-rpc_pipefs.mount local + + 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.1.1/systemd/nfs-mountd.service.orig nfs-utils-2.1.1/systemd/nfs-mountd.service +--- nfs-utils-2.1.1/systemd/nfs-mountd.service.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/nfs-mountd.service 2017-01-16 14:24:01.691124185 -0500 +@@ -6,6 +6,10 @@ After=proc-fs-nfsd.mount + After=network.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.mountd ++ExecStart=/usr/sbin/rpc.mountd $RPCMOUNTDARGS +diff -up nfs-utils-2.1.1/systemd/nfs-server.service.orig nfs-utils-2.1.1/systemd/nfs-server.service +--- nfs-utils-2.1.1/systemd/nfs-server.service.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/nfs-server.service 2017-01-16 14:24:01.692124186 -0500 +@@ -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.1.1/systemd/README.orig nfs-utils-2.1.1/systemd/README +--- nfs-utils-2.1.1/systemd/README.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/README 2017-01-16 14:24:01.691124185 -0500 +@@ -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.1.1/systemd/rpc-gssd.service.in.orig nfs-utils-2.1.1/systemd/rpc-gssd.service.in +--- nfs-utils-2.1.1/systemd/rpc-gssd.service.in.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/rpc-gssd.service.in 2017-01-16 14:24:01.692124186 -0500 +@@ -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.1.1/systemd/rpc-statd-notify.service.orig nfs-utils-2.1.1/systemd/rpc-statd-notify.service +--- nfs-utils-2.1.1/systemd/rpc-statd-notify.service.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/rpc-statd-notify.service 2017-01-16 14:24:01.692124186 -0500 +@@ -10,6 +10,10 @@ After=nfs-server.service + + PartOf=nfs-utils.service + ++Wants=nfs-config.service ++After=nfs-config.service ++ + [Service] ++EnvironmentFile=-/run/sysconfig/nfs-utils + Type=forking +-ExecStart=-/usr/sbin/sm-notify ++ExecStart=-/usr/sbin/sm-notify $SMNOTIFYARGS +diff -up nfs-utils-2.1.1/systemd/rpc-statd.service.orig nfs-utils-2.1.1/systemd/rpc-statd.service +--- nfs-utils-2.1.1/systemd/rpc-statd.service.orig 2017-01-12 10:21:39.000000000 -0500 ++++ nfs-utils-2.1.1/systemd/rpc-statd.service 2017-01-16 14:24:01.692124186 -0500 +@@ -7,8 +7,12 @@ After=network.target nss-lookup.target r + + 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.spec b/nfs-utils.spec index 94a1a2b..c8df509 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 2.1.1 -Release: 0%{?dist} +Release: 1%{?dist} Epoch: 1 # group all 32bit related archs @@ -18,6 +18,7 @@ Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch Patch102: nfs-utils-1.2.3-sm-notify-res_init.patch Patch103: nfs-utils-1.2.5-idmap-errmsg.patch +Patch104: nfs-utils-2.1.1-nfs-config.patch Group: System Environment/Daemons Provides: exportfs = %{epoch}:%{version}-%{release} @@ -74,6 +75,7 @@ This package also contains the mount.nfs and umount.nfs program. %patch101 -p1 %patch102 -p1 %patch103 -p1 +%patch104 -p1 # Remove .orig files find . -name "*.orig" | xargs rm -f @@ -128,9 +130,6 @@ install -m 644 nfs.conf $RPM_BUILD_ROOT%{_sysconfdir} install -m 644 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/request-key.d install -m 644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/nfs -# rpc.svcgssd is no longer supported. -rm -rf $RPM_BUILD_ROOT%{_unitdir}/rpc-svcgssd.service - mkdir -p $RPM_BUILD_ROOT/run/sysconfig mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/scripts install -m 755 %{SOURCE3} $RPM_BUILD_ROOT/usr/libexec/nfs-utils/nfs-utils_env.sh @@ -278,8 +277,11 @@ fi /sbin/umount.nfs4 %changelog +* Thu Jan 19 2017 Steve Dickson 2.1.1-1 +- Added back the nfs-config service for backwards compatibility + * Thu Jan 19 2017 Steve Dickson 2.1.1-0 -- Updated to latest upstream release: nfs-utils-2-1-1 +- Updated to latest upstream release: nfs-utils-2-1-1 (bz 1413232) * Mon Dec 19 2016 Miro HronĨok - 1:1.3.4-1.rc3.1 - Rebuild for Python 3.6 diff --git a/nfs.sysconfig b/nfs.sysconfig index f8370a6..f741989 100644 --- a/nfs.sysconfig +++ b/nfs.sysconfig @@ -35,8 +35,5 @@ RPCGSSDARGS="" # Enable usage of gssproxy. See gssproxy-mech(8). GSS_USE_PROXY="yes" # -# Optional arguments passed to rpc.svcgssd. See rpc.svcgssd(8) -RPCSVCGSSDARGS="" -# # Optional arguments passed to blkmapd. See blkmapd(8) BLKMAPDARGS=""