diff --git a/nfs-utils-1.2.5-idmap-errmsg.patch b/nfs-utils-1.2.5-idmap-errmsg.patch index 3e786c9..958cc30 100644 --- a/nfs-utils-1.2.5-idmap-errmsg.patch +++ b/nfs-utils-1.2.5-idmap-errmsg.patch @@ -1,11 +1,11 @@ diff -up nfs-utils-1.3.3/utils/nfsidmap/nfsidmap.c.orig nfs-utils-1.3.3/utils/nfsidmap/nfsidmap.c ---- nfs-utils-1.3.3/utils/nfsidmap/nfsidmap.c.orig 2015-09-26 10:01:11.000000000 -0400 -+++ nfs-utils-1.3.3/utils/nfsidmap/nfsidmap.c 2015-11-02 09:04:35.380893753 -0500 -@@ -425,7 +425,7 @@ int main(int argc, char **argv) +--- nfs-utils-1.3.3/utils/nfsidmap/nfsidmap.c.orig 2016-03-16 12:29:29.054788094 -0400 ++++ nfs-utils-1.3.3/utils/nfsidmap/nfsidmap.c 2016-03-16 12:31:58.234450259 -0400 +@@ -430,7 +430,7 @@ int main(int argc, char **argv) - 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_err("Bad arg count. Check /etc/request-key.d/request-key.conf"); xlog_warn(usage, progname); return EXIT_FAILURE; diff --git a/nfs-utils-1.3.4-rc3.patch b/nfs-utils-1.3.4-rc3.patch deleted file mode 100644 index 193bc41..0000000 --- a/nfs-utils-1.3.4-rc3.patch +++ /dev/null @@ -1,1389 +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..4daabe9 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -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/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-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/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..e7cb07f 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -556,7 +556,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 +716,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 +820,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 +869,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 +891,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 +920,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..1ef68d8 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; -@@ -231,7 +231,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen, - switch (sa->sa_family) { - case AF_INET: - if (s4->sin_port != 0) { -- printerr(2, "DEBUG: port already set to %d\n", -+ printerr(4, "DEBUG: port already set to %d\n", - ntohs(s4->sin_port)); - return 1; - } -@@ -239,7 +239,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen, - #ifdef IPV6_SUPPORTED - case AF_INET6: - if (s6->sin6_port != 0) { -- printerr(2, "DEBUG: port already set to %d\n", -+ printerr(4, "DEBUG: port already set to %d\n", - ntohs(s6->sin6_port)); - return 1; - } -@@ -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: -@@ -400,7 +393,7 @@ create_auth_rpc_client(struct clnt_info *clp, - auth = authgss_create_default(rpc_clnt, tgtname, &sec); - if (!auth) { - /* Our caller should print appropriate message */ -- printerr(2, "WARNING: Failed to create krb5 context for " -+ printerr(1, "WARNING: Failed to create krb5 context for " - "user with uid %d for server %s\n", - uid, tgtname); - goto out_fail; -@@ -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 { -@@ -608,8 +601,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 +626,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 +639,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 +672,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 +703,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 +746,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 +764,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 +772,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..8ef8184 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 -@@ -801,7 +800,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - 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 (i = 0; myhostad[i] != '$'; ++i) { -+ myhostad[i] = toupper(myhostad[i]); -+ } -+ 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..910b02e 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 [-fvCS] [-p path] [-c path]\n", -+ basename(progname)); -+} -+ - int - main(int argc, char **argv) - { -@@ -232,9 +238,11 @@ main(int argc, char **argv) - 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; -diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man -index c809f78..d45658e 100644 ---- a/utils/idmapd/idmapd.man -+++ b/utils/idmapd/idmapd.man -@@ -10,8 +10,10 @@ - .Sh SYNOPSIS - .\" For a program: program [-abc] file ... - .Nm rpc.idmapd --.Op Fl v - .Op Fl f -+.Op Fl v -+.Op Fl C -+.Op Fl S - .Op Fl p Ar path - .Op Fl c Ar path - .Sh DESCRIPTION -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..86829a9 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; -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/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index a2b11d8..e8efd06 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))) { -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 507193b..15b4a51 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; -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-rc4.patch b/nfs-utils-1.3.4-rc4.patch new file mode 100644 index 0000000..d86d400 --- /dev/null +++ b/nfs-utils-1.3.4-rc4.patch @@ -0,0 +1,1591 @@ +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.spec b/nfs-utils.spec index 3437d8a..741914c 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: 1.3.3 -Release: 6.rc3%{?dist}.1 +Release: 7.rc4%{?dist} Epoch: 1 # group all 32bit related archs @@ -15,7 +15,7 @@ Source2: nfs.sysconfig Source3: nfs-utils_env.sh Source4: lockd.conf -Patch001: nfs-utils-1.3.4-rc3.patch +Patch001: nfs-utils-1.3.4-rc4.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -291,6 +291,9 @@ fi /sbin/umount.nfs4 %changelog +* Wed Mar 16 2016 Steve Dickson 1.3.3-7.rc4 +- Updated to the latest RC release: nfs-utils-1-3-4-rc4 (bz 1316701) + * Thu Feb 04 2016 Fedora Release Engineering - 1:1.3.3-6.rc3.1 - Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild diff --git a/nfs.sysconfig b/nfs.sysconfig index dc54b65..f8370a6 100644 --- a/nfs.sysconfig +++ b/nfs.sysconfig @@ -1,8 +1,4 @@ # -# Note: For new values to take effect the nfs-config service -# has to be restarted with the following command: -# systemctl restart nfs-config -# # Optional arguments passed to in-kernel lockd #LOCKDARG= # TCP port rpc.lockd should listen on.