From b838a8f881ddbee2bd3bd3d76dc9e9753727ef96 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Feb 26 2015 19:52:35 +0000 Subject: Update to latest RC release: nfs-utils-1-3-3-rc1 Signed-off-by: Steve Dickson --- diff --git a/nfs-utils-1-2-9-rc3.patch b/nfs-utils-1-2-9-rc3.patch deleted file mode 100644 index 89b10f4..0000000 --- a/nfs-utils-1-2-9-rc3.patch +++ /dev/null @@ -1,553 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index a594a7b..d3ad854 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1,6 +1,6 @@ - dnl Process this file with autoconf to produce a configure script. - dnl --AC_INIT([linux nfs-utils],[1.2.7],[linux-nfs@vger.kernel.org],[nfs-utils]) -+AC_INIT([linux nfs-utils],[1.2.8],[linux-nfs@vger.kernel.org],[nfs-utils]) - AC_CANONICAL_BUILD([]) - AC_CANONICAL_HOST([]) - AC_CONFIG_MACRO_DIR(aclocal) -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index a0b80e1..1bfae7a 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -156,6 +156,11 @@ extern unsigned long nfs_pmap_getport(const struct sockaddr_in *, - const struct timeval *); - - /* -+ * Use nfs_pmap_getport to see if statd is running locally -+ */ -+extern int nfs_probe_statd(void); -+ -+/* - * Contact a remote RPC service to discover whether it is responding - * to requests. - */ -diff --git a/support/nfs/getport.c b/support/nfs/getport.c -index 3331ad4..081594c 100644 ---- a/support/nfs/getport.c -+++ b/support/nfs/getport.c -@@ -1102,3 +1102,25 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, - - return port; - } -+ -+static const char *nfs_ns_pgmtbl[] = { -+ "status", -+ NULL, -+}; -+ -+/* -+ * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally -+ * -+ * Returns non-zero if statd is running locally. -+ */ -+int nfs_probe_statd(void) -+{ -+ struct sockaddr_in addr = { -+ .sin_family = AF_INET, -+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -+ }; -+ rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -+ -+ return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr), -+ program, (rpcvers_t)1, IPPROTO_UDP); -+} -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index dfbef87..c035537 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -353,14 +353,14 @@ class DeviceData: - exe_per_op = 0.0 - - op += ':' -- print('%s' % op.lower().ljust(15)) -+ print('%s' % op.lower().ljust(15), end='') - print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') - -- print('\t\t%7.3f' % (ops / sample_time)) -- print('\t%7.3f' % (kilobytes / sample_time)) -- print('\t%7.3f' % kb_per_op) -- print(' %7d (%3.1f%%)' % (retrans, retrans_percent)) -- print('\t%7.3f' % rtt_per_op) -+ print('\t\t%7.3f' % (ops / sample_time), end='') -+ print('\t%7.3f' % (kilobytes / sample_time), end='') -+ print('\t%7.3f' % kb_per_op, end='') -+ print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') -+ print('\t%7.3f' % rtt_per_op, end='') - print('\t%7.3f' % exe_per_op) - - def ops(self, sample_time): -@@ -392,7 +392,7 @@ class DeviceData: - print() - - print(' op/s\t\trpc bklog') -- print('%7.2f' % (sends / sample_time)) -+ print('%7.2f' % (sends / sample_time), end='') - print('\t%7.2f' % backlog) - - if which == 0: -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 1df75c5..ac13fd4 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -195,11 +195,28 @@ option when starting - .BR rpc.gssd . - .SH OPTIONS - .TP --.B -D --DNS Reverse lookups are not used for determining the --server names pass to GSSAPI. This option will reverses that and forces --the use of DNS Reverse resolution of the server's IP address to --retrieve the server name to use in GSAPI authentication. -+.B \-D -+The server name passed to GSSAPI for authentication is normally the -+name exactly as requested. e.g. for NFS -+it is the server name in the "servername:/path" mount request. Only if this -+servername appears to be an IP address (IPv4 or IPv6) or an -+unqualified name (no dots) will a reverse DNS lookup -+will be performed to get the canoncial server name. -+ -+If -+.B \-D -+is present, a reverse DNS lookup will -+.I always -+be used, even if the server name looks like a canonical name. So it -+is needed if partially qualified, or non canonical names are regularly -+used. -+ -+Using -+.B \-D -+can introduce a security vulnerability, so it is recommended that -+.B \-D -+not be used, and that canonical names always be used when requesting -+services. - .TP - .B -f - Runs -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index af1844c..b7e2bbb 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -67,7 +67,6 @@ - #include - #include - #include --#include - - #include "gssd.h" - #include "err_util.h" -@@ -176,7 +175,6 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - char *hostname; - char hbuf[NI_MAXHOST]; - unsigned char buf[sizeof(struct in6_addr)]; -- int servername = 0; - - if (avoid_dns) { - /* -@@ -184,15 +182,18 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - * If it is an IP address, do the DNS lookup otherwise - * skip the DNS lookup. - */ -- servername = 0; -- if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1) -- servername = 1; /* IPv4 */ -- else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1) -- servername = 1; /* or IPv6 */ -- -- if (servername) { -+ int is_fqdn = 1; -+ if (strchr(name, '.') == NULL) -+ is_fqdn = 0; /* local name */ -+ else if (inet_pton(AF_INET, name, buf) == 1) -+ is_fqdn = 0; /* IPv4 address */ -+ else if (inet_pton(AF_INET6, name, buf) == 1) -+ is_fqdn = 0; /* IPv6 addrss */ -+ -+ if (is_fqdn) { - return strdup(name); - } -+ /* Sorry, cannot avoid dns after all */ - } - - switch (sa->sa_family) { -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 6275dd8..83b9651 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -231,7 +231,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, - continue; - } - if (uid == 0 && !root_uses_machine_creds && -- strstr(namelist[i]->d_name, "_machine_")) { -+ strstr(namelist[i]->d_name, "machine_")) { - printerr(3, "CC '%s' not available to root\n", - statname); - free(namelist[i]); -@@ -825,8 +825,10 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - - retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) -- goto out; -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - - code = krb5_get_default_realm(context, &default_realm); - if (code) { -@@ -852,11 +854,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - } - - /* -- * Try the "appropriate" realm first, and if nothing found for that -- * realm, try the default realm (if it hasn't already been tried). -+ * Make sure the preferred_realm, which may have been explicitly set -+ * on the command line, is tried first. If nothing is found go on with -+ * the host and local default realm (if that hasn't already been tried). - */ - i = 0; - realm = realmnames[i]; -+ -+ if (strcmp (realm, preferred_realm) != 0) { -+ realm = preferred_realm; -+ /* resetting the realmnames index */ -+ i = -1; -+ } -+ - while (1) { - if (realm == NULL) { - tried_all = 1; -@@ -883,6 +893,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad, - NULL); - } else { -+ if (!myhostname[0]) -+ continue; - snprintf(spn, sizeof(spn), "%s/%s@%s", - svcnames[j], myhostname, realm); - code = krb5_build_principal_ext(context, &princ, -@@ -1236,7 +1248,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, - krb5_keytab kt = NULL;; - int retval = 0; - char *k5err = NULL; -- const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; -+ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - - /* - * If a specific service name was specified, use it. -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 4be48cd..e2cdcaf 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -65,11 +65,6 @@ extern int nfs_mount_data_version; - extern char *progname; - extern int verbose; - --static const char *nfs_ns_pgmtbl[] = { -- "status", -- NULL, --}; -- - static const char *nfs_mnt_pgmtbl[] = { - "mount", - "mountd", -@@ -761,18 +756,6 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) - &nfs_server->pmap); - } - --static int nfs_probe_statd(void) --{ -- struct sockaddr_in addr = { -- .sin_family = AF_INET, -- .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -- }; -- rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -- -- return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), -- program, (rpcvers_t)1, IPPROTO_UDP); --} -- - /** - * start_statd - attempt to start rpc.statd - * -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index a8ec46c..2a42b93 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -84,6 +84,20 @@ in - .SS "Options supported by all versions" - These options are valid to use with any NFS version. - .TP 1.5i -+.BI nfsvers= n -+The NFS protocol version number used to contact the server's NFS service. -+If the server does not support the requested version, the mount request -+fails. -+If this option is not specified, the client negotiates a suitable version -+with -+the server, trying version 4 first, version 3 second, and version 2 last. -+.TP 1.5i -+.BI vers= n -+This option is an alternative to the -+.B nfsvers -+option. -+It is included for compatibility with other operating systems -+.TP 1.5i - .BR soft " / " hard - Determines the recovery behavior of the NFS client - after an NFS request times out. -@@ -621,18 +635,6 @@ Using this option ensures that - reports the proper maximum component length to applications - in such cases. - .TP 1.5i --.BI nfsvers= n --The NFS protocol version number used to contact the server's NFS service. --If the server does not support the requested version, the mount request fails. --If this option is not specified, the client negotiates a suitable version with --the server, trying version 4 first, version 3 second, and version 2 last. --.TP 1.5i --.BI vers= n --This option is an alternative to the --.B nfsvers --option. --It is included for compatibility with other operating systems. --.TP 1.5i - .BR lock " / " nolock - Selects whether to use the NLM sideband protocol to lock files on the server. - If neither option is specified (or if -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 737927c..517aa62 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -347,20 +347,26 @@ static char *next_mnt(void **v, char *p) - - static int is_subdirectory(char *child, char *parent) - { -+ /* Check is child is strictly a subdirectory of -+ * parent or a more distant descendant. -+ */ - size_t l = strlen(parent); - -- if (strcmp(parent, "/") == 0) -+ if (strcmp(parent, "/") == 0 && child[1] != 0) - return 1; - -- return strcmp(child, parent) == 0 -- || (strncmp(child, parent, l) == 0 && child[l] == '/'); -+ return (strncmp(child, parent, l) == 0 && child[l] == '/'); - } - - static int path_matches(nfs_export *exp, char *path) - { -- if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -- return is_subdirectory(path, exp->m_export.e_path); -- return strcmp(path, exp->m_export.e_path) == 0; -+ /* Does the path match the export? I.e. is it an -+ * exact match, or does the export have CROSSMOUNT, and path -+ * is a descendant? -+ */ -+ return strcmp(path, exp->m_export.e_path) == 0 -+ || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -+ && is_subdirectory(path, exp->m_export.e_path)); - } - - static int -@@ -369,15 +375,13 @@ export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) - return path_matches(exp, path) && client_matches(exp, dom, ai); - } - --/* True iff e1 is a child of e2 and e2 has crossmnt set: */ -+/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */ - static bool subexport(struct exportent *e1, struct exportent *e2) - { - char *p1 = e1->e_path, *p2 = e2->e_path; -- size_t l2 = strlen(p2); - - return e2->e_flags & NFSEXP_CROSSMOUNT -- && strncmp(p1, p2, l2) == 0 -- && p1[l2] == '/'; -+ && is_subdirectory(p1, p2); - } - - struct parsed_fsid { -diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man -index 47007df..6940788 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.man -+++ b/utils/nfsdcltrack/nfsdcltrack.man -@@ -1,53 +1,3 @@ --.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) --.\" --.\" Standard preamble: --.\" ======================================================================== --.de Sp \" Vertical space (when we can't use .PP) --.if t .sp .5v --.if n .sp --.. --.de Vb \" Begin verbatim text --.ft CW --.nf --.ne \\$1 --.. --.de Ve \" End verbatim text --.ft R --.fi --.. --.\" Set up some character translations and predefined strings. \*(-- will --.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left --.\" double quote, and \*(R" will give a right double quote. \*(C+ will --.\" give a nicer C++. Capital omega is used to do unbreakable dashes and --.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, --.\" nothing in troff, for use with C<>. --.tr \(*W- --.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' --.ie n \{\ --. ds -- \(*W- --. ds PI pi --. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch --. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch --. ds L" "" --. ds R" "" --. ds C` "" --. ds C' "" --'br\} --.el\{\ --. ds -- \|\(em\| --. ds PI \(*p --. ds L" `` --. ds R" '' --'br\} --.\" --.\" Escape single quotes in literal strings from groff's Unicode transform. --.ie \n(.g .ds Aq \(aq --.el .ds Aq ' --.\" --.\" If the F register is turned on, we'll generate index entries on stderr for --.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index --.\" entries marked with X<> in POD. Of course, you'll have to process the --.\" output yourself in some meaningful fashion. - .ie \nF \{\ - . de IX - . tm Index:\\$1\t\\n%\t"\\$2" -@@ -59,70 +9,6 @@ - . de IX - .. - .\} --.\" --.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). --.\" Fear. Run. Save yourself. No user-serviceable parts. --. \" fudge factors for nroff and troff --.if n \{\ --. ds #H 0 --. ds #V .8m --. ds #F .3m --. ds #[ \f1 --. ds #] \fP --.\} --.if t \{\ --. ds #H ((1u-(\\\\n(.fu%2u))*.13m) --. ds #V .6m --. ds #F 0 --. ds #[ \& --. ds #] \& --.\} --. \" simple accents for nroff and troff --.if n \{\ --. ds ' \& --. ds ` \& --. ds ^ \& --. ds , \& --. ds ~ ~ --. ds / --.\} --.if t \{\ --. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" --. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' --. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' --. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' --. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' --. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' --.\} --. \" troff and (daisy-wheel) nroff accents --.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' --.ds 8 \h'\*(#H'\(*b\h'-\*(#H' --.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] --.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' --.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' --.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] --.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] --.ds ae a\h'-(\w'a'u*4/10)'e --.ds Ae A\h'-(\w'A'u*4/10)'E --. \" corrections for vroff --.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' --.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' --. \" for low resolution devices (crt and lpr) --.if \n(.H>23 .if \n(.V>19 \ --\{\ --. ds : e --. ds 8 ss --. ds o a --. ds d- d\h'-1'\(ga --. ds D- D\h'-1'\(hy --. ds th \o'bp' --. ds Th \o'LP' --. ds ae ae --. ds Ae AE --.\} --.rm #[ #] #H #V #F C --.\" ======================================================================== --.\" - .IX Title "NFSDCLTRACK 8" - .TH NFSDCLTRACK 8 "2012-10-24" "" "" - .\" For nroff, turn off justification. Always turn off hyphenation; it makes -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index c0675c4..737a219 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -1,9 +1,10 @@ - ## Process this file with automake to produce Makefile.in - - man8_MANS = nfsidmap.man -- - sbin_PROGRAMS = nfsidmap -+ - nfsidmap_SOURCES = nfsidmap.c - nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -+EXTRA_DIST = id_resolver.conf -diff --git a/utils/nfsidmap/id_resolver.conf b/utils/nfsidmap/id_resolver.conf -new file mode 100644 -index 0000000..2c156c6 ---- /dev/null -+++ b/utils/nfsidmap/id_resolver.conf -@@ -0,0 +1 @@ -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 652546c..8c51bcc 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -28,6 +28,7 @@ - - #include "statd.h" - #include "nfslib.h" -+#include "nfsrpc.h" - #include "nsm.h" - - /* Socket operations */ -@@ -237,6 +238,12 @@ int main (int argc, char **argv) - /* Set hostname */ - MY_NAME = NULL; - -+ /* Refuse to start if another statd is running */ -+ if (nfs_probe_statd()) { -+ fprintf(stderr, "Statd service already running!\n"); -+ exit(1); -+ } -+ - /* Process command line switches */ - while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { - switch (arg) { diff --git a/nfs-utils-1-2-9-rc4.patch b/nfs-utils-1-2-9-rc4.patch deleted file mode 100644 index ff965fc..0000000 --- a/nfs-utils-1-2-9-rc4.patch +++ /dev/null @@ -1,757 +0,0 @@ -diff --git a/support/include/conffile.h b/support/include/conffile.h -index ce7aa21..05ea5d2 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -54,7 +54,7 @@ extern int conf_end(int, int); - extern void conf_free_list(struct conf_list *); - extern struct sockaddr *conf_get_address(char *, char *); - extern struct conf_list *conf_get_list(char *, char *); --extern struct conf_list *conf_get_tag_list(char *); -+extern struct conf_list *conf_get_tag_list(char *, char *); - extern int conf_get_num(char *, char *, int); - extern char *conf_get_str(char *, char *); - extern char *conf_get_section(char *, char *, char *); -diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h -index 174c2dd..38db5b5 100644 ---- a/support/include/nfs/nfs.h -+++ b/support/include/nfs/nfs.h -@@ -15,6 +15,10 @@ - #define NFSD_MINVERS 2 - #define NFSD_MAXVERS 4 - -+#define NFS4_MINMINOR 1 -+#define NFS4_MAXMINOR 2 -+#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */ -+ - struct nfs_fh_len { - int fh_size; - u_int8_t fh_handle[NFS3_FHSIZE]; -@@ -52,6 +56,7 @@ struct nfs_fh_old { - #define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) - #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) - -+#define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ - #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) - #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) - #define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index a0b80e1..1bfae7a 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -156,6 +156,11 @@ extern unsigned long nfs_pmap_getport(const struct sockaddr_in *, - const struct timeval *); - - /* -+ * Use nfs_pmap_getport to see if statd is running locally -+ */ -+extern int nfs_probe_statd(void); -+ -+/* - * Contact a remote RPC service to discover whether it is responding - * to requests. - */ -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 5015e94..c3434d5 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -565,7 +565,7 @@ cleanup: - } - - struct conf_list * --conf_get_tag_list(char *section) -+conf_get_tag_list(char *section, char *arg) - { - struct conf_list *list = 0; - struct conf_list_node *node; -@@ -579,6 +579,8 @@ conf_get_tag_list(char *section) - cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); - for (; cb; cb = LIST_NEXT(cb, link)) { - if (strcasecmp (section, cb->section) == 0) { -+ if (arg != NULL && strcasecmp(arg, cb->arg) != 0) -+ continue; - list->cnt++; - node = calloc(1, sizeof *node); - if (!node) -diff --git a/support/nfs/getport.c b/support/nfs/getport.c -index 3331ad4..081594c 100644 ---- a/support/nfs/getport.c -+++ b/support/nfs/getport.c -@@ -1102,3 +1102,25 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, - - return port; - } -+ -+static const char *nfs_ns_pgmtbl[] = { -+ "status", -+ NULL, -+}; -+ -+/* -+ * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally -+ * -+ * Returns non-zero if statd is running locally. -+ */ -+int nfs_probe_statd(void) -+{ -+ struct sockaddr_in addr = { -+ .sin_family = AF_INET, -+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -+ }; -+ rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -+ -+ return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr), -+ program, (rpcvers_t)1, IPPROTO_UDP); -+} -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index dfbef87..c035537 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -353,14 +353,14 @@ class DeviceData: - exe_per_op = 0.0 - - op += ':' -- print('%s' % op.lower().ljust(15)) -+ print('%s' % op.lower().ljust(15), end='') - print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') - -- print('\t\t%7.3f' % (ops / sample_time)) -- print('\t%7.3f' % (kilobytes / sample_time)) -- print('\t%7.3f' % kb_per_op) -- print(' %7d (%3.1f%%)' % (retrans, retrans_percent)) -- print('\t%7.3f' % rtt_per_op) -+ print('\t\t%7.3f' % (ops / sample_time), end='') -+ print('\t%7.3f' % (kilobytes / sample_time), end='') -+ print('\t%7.3f' % kb_per_op, end='') -+ print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') -+ print('\t%7.3f' % rtt_per_op, end='') - print('\t%7.3f' % exe_per_op) - - def ops(self, sample_time): -@@ -392,7 +392,7 @@ class DeviceData: - print() - - print(' op/s\t\trpc bklog') -- print('%7.2f' % (sends / sample_time)) -+ print('%7.2f' % (sends / sample_time), end='') - print('\t%7.2f' % backlog) - - if which == 0: -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 1df75c5..ac13fd4 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -195,11 +195,28 @@ option when starting - .BR rpc.gssd . - .SH OPTIONS - .TP --.B -D --DNS Reverse lookups are not used for determining the --server names pass to GSSAPI. This option will reverses that and forces --the use of DNS Reverse resolution of the server's IP address to --retrieve the server name to use in GSAPI authentication. -+.B \-D -+The server name passed to GSSAPI for authentication is normally the -+name exactly as requested. e.g. for NFS -+it is the server name in the "servername:/path" mount request. Only if this -+servername appears to be an IP address (IPv4 or IPv6) or an -+unqualified name (no dots) will a reverse DNS lookup -+will be performed to get the canoncial server name. -+ -+If -+.B \-D -+is present, a reverse DNS lookup will -+.I always -+be used, even if the server name looks like a canonical name. So it -+is needed if partially qualified, or non canonical names are regularly -+used. -+ -+Using -+.B \-D -+can introduce a security vulnerability, so it is recommended that -+.B \-D -+not be used, and that canonical names always be used when requesting -+services. - .TP - .B -f - Runs -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index af1844c..b7e2bbb 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -67,7 +67,6 @@ - #include - #include - #include --#include - - #include "gssd.h" - #include "err_util.h" -@@ -176,7 +175,6 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - char *hostname; - char hbuf[NI_MAXHOST]; - unsigned char buf[sizeof(struct in6_addr)]; -- int servername = 0; - - if (avoid_dns) { - /* -@@ -184,15 +182,18 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - * If it is an IP address, do the DNS lookup otherwise - * skip the DNS lookup. - */ -- servername = 0; -- if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1) -- servername = 1; /* IPv4 */ -- else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1) -- servername = 1; /* or IPv6 */ -- -- if (servername) { -+ int is_fqdn = 1; -+ if (strchr(name, '.') == NULL) -+ is_fqdn = 0; /* local name */ -+ else if (inet_pton(AF_INET, name, buf) == 1) -+ is_fqdn = 0; /* IPv4 address */ -+ else if (inet_pton(AF_INET6, name, buf) == 1) -+ is_fqdn = 0; /* IPv6 addrss */ -+ -+ if (is_fqdn) { - return strdup(name); - } -+ /* Sorry, cannot avoid dns after all */ - } - - switch (sa->sa_family) { -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 6275dd8..83b9651 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -231,7 +231,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, - continue; - } - if (uid == 0 && !root_uses_machine_creds && -- strstr(namelist[i]->d_name, "_machine_")) { -+ strstr(namelist[i]->d_name, "machine_")) { - printerr(3, "CC '%s' not available to root\n", - statname); - free(namelist[i]); -@@ -825,8 +825,10 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - - retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) -- goto out; -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - - code = krb5_get_default_realm(context, &default_realm); - if (code) { -@@ -852,11 +854,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - } - - /* -- * Try the "appropriate" realm first, and if nothing found for that -- * realm, try the default realm (if it hasn't already been tried). -+ * Make sure the preferred_realm, which may have been explicitly set -+ * on the command line, is tried first. If nothing is found go on with -+ * the host and local default realm (if that hasn't already been tried). - */ - i = 0; - realm = realmnames[i]; -+ -+ if (strcmp (realm, preferred_realm) != 0) { -+ realm = preferred_realm; -+ /* resetting the realmnames index */ -+ i = -1; -+ } -+ - while (1) { - if (realm == NULL) { - tried_all = 1; -@@ -883,6 +893,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad, - NULL); - } else { -+ if (!myhostname[0]) -+ continue; - snprintf(spn, sizeof(spn), "%s/%s@%s", - svcnames[j], myhostname, realm); - code = krb5_build_principal_ext(context, &princ, -@@ -1236,7 +1248,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, - krb5_keytab kt = NULL;; - int retval = 0; - char *k5err = NULL; -- const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; -+ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - - /* - * If a specific service name was specified, use it. -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index beba9c4..b6c6231 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -502,7 +502,7 @@ nfsdcb(int UNUSED(fd), short which, void *data) - struct idmap_client *ic = data; - struct idmap_msg im; - u_char buf[IDMAP_MAXMSGSZ + 1]; -- size_t len; -+ ssize_t len; - ssize_t bsiz; - char *bp, typebuf[IDMAP_MAXMSGSZ], - buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; -@@ -511,10 +511,14 @@ nfsdcb(int UNUSED(fd), short which, void *data) - if (which != EV_READ) - goto out; - -- if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) { -+ len = read(ic->ic_fd, buf, sizeof(buf)); -+ if (len == 0) -+ /* No upcall to read; not necessarily a problem: */ -+ return; -+ if (len < 0) { - xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)", -- ic->ic_path, len?errno:0, -- len?strerror(errno):"End of File"); -+ ic->ic_path, errno, -+ strerror(errno)); - nfsdreopen_one(ic); - return; - } -diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c -index 6f2ee75..68b9f93 100644 ---- a/utils/mount/configfile.c -+++ b/utils/mount/configfile.c -@@ -73,6 +73,8 @@ struct mnt_alias { - }; - int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); - -+static int strict; -+ - /* - * See if the option is an alias, if so return the - * real mount option along with the argument type. -@@ -286,7 +288,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - char *nvalue, *ptr; - int argtype; - -- list = conf_get_tag_list(section); -+ list = conf_get_tag_list(section, arg); - TAILQ_FOREACH(node, &list->fields, link) { - /* - * Do not overwrite options if already exists -@@ -310,7 +312,15 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - if (strcasecmp(value, "false") == 0) { - if (argtype != MNT_NOARG) - snprintf(buf, BUFSIZ, "no%s", field); -+ else if (strcasecmp(field, "bg") == 0) -+ snprintf(buf, BUFSIZ, "fg"); -+ else if (strcasecmp(field, "fg") == 0) -+ snprintf(buf, BUFSIZ, "bg"); -+ else if (strcasecmp(field, "sloppy") == 0) -+ strict = 1; - } else if (strcasecmp(value, "true") == 0) { -+ if ((strcasecmp(field, "sloppy") == 0) && strict) -+ continue; - snprintf(buf, BUFSIZ, "%s", field); - } else { - nvalue = strdup(value); -@@ -345,6 +355,7 @@ char *conf_get_mntopts(char *spec, char *mount_point, - char *ptr, *server, *config_opts; - int optlen = 0; - -+ strict = 0; - SLIST_INIT(&head); - list_size = 0; - /* -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 4be48cd..e2cdcaf 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -65,11 +65,6 @@ extern int nfs_mount_data_version; - extern char *progname; - extern int verbose; - --static const char *nfs_ns_pgmtbl[] = { -- "status", -- NULL, --}; -- - static const char *nfs_mnt_pgmtbl[] = { - "mount", - "mountd", -@@ -761,18 +756,6 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) - &nfs_server->pmap); - } - --static int nfs_probe_statd(void) --{ -- struct sockaddr_in addr = { -- .sin_family = AF_INET, -- .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -- }; -- rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -- -- return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), -- program, (rpcvers_t)1, IPPROTO_UDP); --} -- - /** - * start_statd - attempt to start rpc.statd - * -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index a8ec46c..2a42b93 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -84,6 +84,20 @@ in - .SS "Options supported by all versions" - These options are valid to use with any NFS version. - .TP 1.5i -+.BI nfsvers= n -+The NFS protocol version number used to contact the server's NFS service. -+If the server does not support the requested version, the mount request -+fails. -+If this option is not specified, the client negotiates a suitable version -+with -+the server, trying version 4 first, version 3 second, and version 2 last. -+.TP 1.5i -+.BI vers= n -+This option is an alternative to the -+.B nfsvers -+option. -+It is included for compatibility with other operating systems -+.TP 1.5i - .BR soft " / " hard - Determines the recovery behavior of the NFS client - after an NFS request times out. -@@ -621,18 +635,6 @@ Using this option ensures that - reports the proper maximum component length to applications - in such cases. - .TP 1.5i --.BI nfsvers= n --The NFS protocol version number used to contact the server's NFS service. --If the server does not support the requested version, the mount request fails. --If this option is not specified, the client negotiates a suitable version with --the server, trying version 4 first, version 3 second, and version 2 last. --.TP 1.5i --.BI vers= n --This option is an alternative to the --.B nfsvers --option. --It is included for compatibility with other operating systems. --.TP 1.5i - .BR lock " / " nolock - Selects whether to use the NLM sideband protocol to lock files on the server. - If neither option is specified (or if -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 737927c..517aa62 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -347,20 +347,26 @@ static char *next_mnt(void **v, char *p) - - static int is_subdirectory(char *child, char *parent) - { -+ /* Check is child is strictly a subdirectory of -+ * parent or a more distant descendant. -+ */ - size_t l = strlen(parent); - -- if (strcmp(parent, "/") == 0) -+ if (strcmp(parent, "/") == 0 && child[1] != 0) - return 1; - -- return strcmp(child, parent) == 0 -- || (strncmp(child, parent, l) == 0 && child[l] == '/'); -+ return (strncmp(child, parent, l) == 0 && child[l] == '/'); - } - - static int path_matches(nfs_export *exp, char *path) - { -- if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -- return is_subdirectory(path, exp->m_export.e_path); -- return strcmp(path, exp->m_export.e_path) == 0; -+ /* Does the path match the export? I.e. is it an -+ * exact match, or does the export have CROSSMOUNT, and path -+ * is a descendant? -+ */ -+ return strcmp(path, exp->m_export.e_path) == 0 -+ || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -+ && is_subdirectory(path, exp->m_export.e_path)); - } - - static int -@@ -369,15 +375,13 @@ export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) - return path_matches(exp, path) && client_matches(exp, dom, ai); - } - --/* True iff e1 is a child of e2 and e2 has crossmnt set: */ -+/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */ - static bool subexport(struct exportent *e1, struct exportent *e2) - { - char *p1 = e1->e_path, *p2 = e2->e_path; -- size_t l2 = strlen(p2); - - return e2->e_flags & NFSEXP_CROSSMOUNT -- && strncmp(p1, p2, l2) == 0 -- && p1[l2] == '/'; -+ && is_subdirectory(p1, p2); - } - - struct parsed_fsid { -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index e87c0a9..6db92f0 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -99,8 +99,8 @@ main(int argc, char **argv) - char *p, *progname, *port; - char *haddr = NULL; - int socket_up = 0; -- int minorvers41 = 0; /* nfsv4 minor version */ -- unsigned int versbits = NFSCTL_ALLBITS; -+ int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */ -+ unsigned int versbits = NFSCTL_VERDEFAULT; - unsigned int protobits = NFSCTL_ALLBITS; - unsigned int proto4 = 0; - unsigned int proto6 = 0; -@@ -160,11 +160,11 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i != 1) { -+ if (i > 2) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- minorvers41 = -1; -+ NFSCTL_VERUNSET(minorvers, i); - break; - } - case 3: -@@ -181,11 +181,11 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i != 1) { -+ if (i > 2) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- minorvers41 = 1; -+ NFSCTL_VERSET(minorvers, i); - break; - } - case 3: -@@ -282,7 +282,7 @@ main(int argc, char **argv) - * registered with rpcbind. Note that on older kernels w/o the right - * interfaces, these are a no-op. - */ -- nfssvc_setvers(versbits, minorvers41); -+ nfssvc_setvers(versbits, minorvers); - - error = nfssvc_set_sockets(AF_INET, proto4, haddr, port); - if (!error) -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 683008e..8b85846 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits, - } - - void --nfssvc_setvers(unsigned int ctlbits, int minorvers41) -+nfssvc_setvers(unsigned int ctlbits, int minorvers) - { - int fd, n, off; - char *ptr; -@@ -280,9 +280,12 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers41) - if (fd < 0) - return; - -- if (minorvers41) -- off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1", -- minorvers41 > 0 ? '+' : '-'); -+ for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { -+ if (NFSCTL_VERISSET(minorvers, n)) -+ off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); -+ else -+ off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); -+ } - for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { - if (NFSCTL_VERISSET(ctlbits, n)) - off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); -diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man -index 47007df..6940788 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.man -+++ b/utils/nfsdcltrack/nfsdcltrack.man -@@ -1,53 +1,3 @@ --.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) --.\" --.\" Standard preamble: --.\" ======================================================================== --.de Sp \" Vertical space (when we can't use .PP) --.if t .sp .5v --.if n .sp --.. --.de Vb \" Begin verbatim text --.ft CW --.nf --.ne \\$1 --.. --.de Ve \" End verbatim text --.ft R --.fi --.. --.\" Set up some character translations and predefined strings. \*(-- will --.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left --.\" double quote, and \*(R" will give a right double quote. \*(C+ will --.\" give a nicer C++. Capital omega is used to do unbreakable dashes and --.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, --.\" nothing in troff, for use with C<>. --.tr \(*W- --.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' --.ie n \{\ --. ds -- \(*W- --. ds PI pi --. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch --. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch --. ds L" "" --. ds R" "" --. ds C` "" --. ds C' "" --'br\} --.el\{\ --. ds -- \|\(em\| --. ds PI \(*p --. ds L" `` --. ds R" '' --'br\} --.\" --.\" Escape single quotes in literal strings from groff's Unicode transform. --.ie \n(.g .ds Aq \(aq --.el .ds Aq ' --.\" --.\" If the F register is turned on, we'll generate index entries on stderr for --.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index --.\" entries marked with X<> in POD. Of course, you'll have to process the --.\" output yourself in some meaningful fashion. - .ie \nF \{\ - . de IX - . tm Index:\\$1\t\\n%\t"\\$2" -@@ -59,70 +9,6 @@ - . de IX - .. - .\} --.\" --.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). --.\" Fear. Run. Save yourself. No user-serviceable parts. --. \" fudge factors for nroff and troff --.if n \{\ --. ds #H 0 --. ds #V .8m --. ds #F .3m --. ds #[ \f1 --. ds #] \fP --.\} --.if t \{\ --. ds #H ((1u-(\\\\n(.fu%2u))*.13m) --. ds #V .6m --. ds #F 0 --. ds #[ \& --. ds #] \& --.\} --. \" simple accents for nroff and troff --.if n \{\ --. ds ' \& --. ds ` \& --. ds ^ \& --. ds , \& --. ds ~ ~ --. ds / --.\} --.if t \{\ --. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" --. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' --. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' --. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' --. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' --. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' --.\} --. \" troff and (daisy-wheel) nroff accents --.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' --.ds 8 \h'\*(#H'\(*b\h'-\*(#H' --.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] --.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' --.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' --.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] --.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] --.ds ae a\h'-(\w'a'u*4/10)'e --.ds Ae A\h'-(\w'A'u*4/10)'E --. \" corrections for vroff --.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' --.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' --. \" for low resolution devices (crt and lpr) --.if \n(.H>23 .if \n(.V>19 \ --\{\ --. ds : e --. ds 8 ss --. ds o a --. ds d- d\h'-1'\(ga --. ds D- D\h'-1'\(hy --. ds th \o'bp' --. ds Th \o'LP' --. ds ae ae --. ds Ae AE --.\} --.rm #[ #] #H #V #F C --.\" ======================================================================== --.\" - .IX Title "NFSDCLTRACK 8" - .TH NFSDCLTRACK 8 "2012-10-24" "" "" - .\" For nroff, turn off justification. Always turn off hyphenation; it makes -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index c0675c4..737a219 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -1,9 +1,10 @@ - ## Process this file with automake to produce Makefile.in - - man8_MANS = nfsidmap.man -- - sbin_PROGRAMS = nfsidmap -+ - nfsidmap_SOURCES = nfsidmap.c - nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -+EXTRA_DIST = id_resolver.conf -diff --git a/utils/nfsidmap/id_resolver.conf b/utils/nfsidmap/id_resolver.conf -new file mode 100644 -index 0000000..2c156c6 ---- /dev/null -+++ b/utils/nfsidmap/id_resolver.conf -@@ -0,0 +1 @@ -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 652546c..8c51bcc 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -28,6 +28,7 @@ - - #include "statd.h" - #include "nfslib.h" -+#include "nfsrpc.h" - #include "nsm.h" - - /* Socket operations */ -@@ -237,6 +238,12 @@ int main (int argc, char **argv) - /* Set hostname */ - MY_NAME = NULL; - -+ /* Refuse to start if another statd is running */ -+ if (nfs_probe_statd()) { -+ fprintf(stderr, "Statd service already running!\n"); -+ exit(1); -+ } -+ - /* Process command line switches */ - while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { - switch (arg) { diff --git a/nfs-utils-1.2.10-rc2.patch b/nfs-utils-1.2.10-rc2.patch deleted file mode 100644 index d55ef39..0000000 --- a/nfs-utils-1.2.10-rc2.patch +++ /dev/null @@ -1,1058 +0,0 @@ -diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h -index 38db5b5..df4ad76 100644 ---- a/support/include/nfs/nfs.h -+++ b/support/include/nfs/nfs.h -@@ -17,7 +17,6 @@ - - #define NFS4_MINMINOR 1 - #define NFS4_MAXMINOR 2 --#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */ - - struct nfs_fh_len { - int fh_size; -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index f210a06..ce4b14b 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -128,6 +128,10 @@ void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos); - void fendrmtabent(FILE *fp); - void frewindrmtabent(FILE *fp); - -+/* mydaemon */ -+void mydaemon(int nochdir, int noclose, int *pipefds); -+void release_parent(int *pipefds); -+ - /* - * wildmat borrowed from INN - */ -diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am -index 05c2fc4..fb9b8c1 100644 ---- a/support/nfs/Makefile.am -+++ b/support/nfs/Makefile.am -@@ -2,7 +2,7 @@ - - noinst_LIBRARIES = libnfs.a - libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ -- xlog.c xcommon.c wildmat.c nfsclient.c \ -+ xlog.c xcommon.c wildmat.c mydaemon.c nfsclient.c \ - nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ - svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \ - svc_create.c atomicio.c strlcpy.c strlcat.c -diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c -new file mode 100644 -index 0000000..e885d60 ---- /dev/null -+++ b/support/nfs/mydaemon.c -@@ -0,0 +1,148 @@ -+/* -+ mydaemon.c -+ -+ Copyright (c) 2000 The Regents of the University of Michigan. -+ All rights reserved. -+ -+ Copyright (c) 2000 Dug Song . -+ Copyright (c) 2002 Andy Adamson . -+ Copyright (c) 2002 Marius Aamodt Eriksen . -+ Copyright (c) 2002 J. Bruce Fields . -+ Copyright (c) 2013 Jeff Layton -+ -+ All rights reserved, all wrongs reversed. -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions -+ are met: -+ -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ 2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+ 3. Neither the name of the University nor the names of its -+ contributors may be used to endorse or promote products derived -+ from this software without specific prior written permission. -+ -+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * mydaemon - daemonize, but have parent wait to exit -+ * @nochdir: skip chdir()'ing the child to / after forking if true -+ * @noclose: skip closing stdin/stdout/stderr if true -+ * @pipefds: pointer to 2 element array of pipefds -+ * -+ * This function is like daemon(), but with our own special sauce to delay -+ * the exit of the parent until the child is set up properly. A pipe is created -+ * between parent and child. The parent process will wait to exit until the -+ * child dies or writes a '1' on the pipe signaling that it started -+ * successfully. -+ */ -+void -+mydaemon(int nochdir, int noclose, int *pipefds) -+{ -+ int pid, status, tempfd; -+ -+ if (pipe(pipefds) < 0) { -+ xlog_err("mydaemon: pipe() failed: errno %d (%s)\n", -+ errno, strerror(errno)); -+ exit(1); -+ } -+ if ((pid = fork ()) < 0) { -+ xlog_err("mydaemon: fork() failed: errno %d (%s)\n", -+ errno, strerror(errno)); -+ exit(1); -+ } -+ -+ if (pid != 0) { -+ /* -+ * Parent. Wait for status from child. -+ */ -+ close(pipefds[1]); -+ if (read(pipefds[0], &status, 1) != 1) -+ exit(1); -+ exit (0); -+ } -+ /* Child. */ -+ close(pipefds[0]); -+ setsid (); -+ if (nochdir == 0) { -+ if (chdir ("/") == -1) { -+ xlog_err("mydaemon: chdir() failed: errno %d (%s)\n", -+ errno, strerror(errno)); -+ exit(1); -+ } -+ } -+ -+ while (pipefds[1] <= 2) { -+ pipefds[1] = dup(pipefds[1]); -+ if (pipefds[1] < 0) { -+ xlog_err("mydaemon: dup() failed: errno %d (%s)\n", -+ errno, strerror(errno)); -+ exit(1); -+ } -+ } -+ -+ if (noclose == 0) { -+ tempfd = open("/dev/null", O_RDWR); -+ if (tempfd >= 0) { -+ dup2(tempfd, 0); -+ dup2(tempfd, 1); -+ dup2(tempfd, 2); -+ close(tempfd); -+ } else { -+ xlog_err("mydaemon: can't open /dev/null: errno %d " -+ "(%s)\n", errno, strerror(errno)); -+ exit(1); -+ } -+ } -+ -+ return; -+} -+ -+/** -+ * release_parent - tell the parent that it can exit now -+ * @pipefds: pipefd array that was previously passed to mydaemon() -+ * -+ * This function tells the parent process of mydaemon() that it's now clear -+ * to exit(0). -+ */ -+void -+release_parent(int *pipefds) -+{ -+ int status; -+ -+ if (pipefds[1] > 0) { -+ if (write(pipefds[1], &status, 1) != 1) { -+ xlog_err("WARN: writing to parent pipe failed: errno " -+ "%d (%s)\n", errno, strerror(errno)); -+ } -+ close(pipefds[1]); -+ pipefds[1] = -1; -+ } -+} -+ -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index da5fe21..9ea86cb 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -27,6 +27,10 @@ - #include - #include - #include -+#include -+#include -+ -+#define INT_TO_LONG_THRESHOLD_SECS (INT_MAX - (60 * 60 * 24)) - - #include "sockaddr.h" - #include "misc.h" -@@ -61,19 +65,19 @@ static int _lockfd = -1; - * writes A+B writes A+C - * - * The locking in support/export/xtab.c will prevent mountd from -- * seeing a partially written version of etab, and will prevent -+ * seeing a partially written version of etab, and will prevent - * the two writers above from writing simultaneously and - * corrupting etab, but to prevent problems like the above we - * need these additional lockfile() routines. - */ --static void -+static void - grab_lockfile() - { - _lockfd = open(lockfile, O_CREAT|O_RDWR, 0666); -- if (_lockfd != -1) -+ if (_lockfd != -1) - lockf(_lockfd, F_LOCK, 0); - } --static void -+static void - release_lockfile() - { - if (_lockfd != -1) -@@ -267,7 +271,7 @@ exports_update(int verbose) - exports_update_one(exp, verbose); - } - } -- -+ - /* - * export_all finds all entries and - * marks them xtabent and mayexport so that they get exported -@@ -282,7 +286,7 @@ export_all(int verbose) - for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { - if (verbose) - printf("exporting %s:%s\n", -- exp->m_client->m_hostname, -+ exp->m_client->m_hostname, - exp->m_export.e_path); - exp->m_xtabent = 1; - exp->m_mayexport = 1; -@@ -329,7 +333,7 @@ exportfs(char *arg, char *options, int verbose) - goto out; - - if (verbose) -- printf("exporting %s:%s\n", exp->m_client->m_hostname, -+ printf("exporting %s:%s\n", exp->m_client->m_hostname, - exp->m_export.e_path); - exp->m_xtabent = 1; - exp->m_mayexport = 1; -@@ -387,7 +391,7 @@ unexportfs(char *arg, int verbose) - else - #endif - printf("unexporting %s:%s\n", -- exp->m_client->m_hostname, -+ exp->m_client->m_hostname, - exp->m_export.e_path); - } - #if 0 -@@ -398,7 +402,7 @@ unexportfs(char *arg, int verbose) - exp->m_mayexport = 0; - success = 1; - } -- if (!success) -+ if (!success) - xlog(L_ERROR, "Could not find '%s:%s' to unexport.", arg, path); - - freeaddrinfo(ai); -@@ -406,17 +410,33 @@ unexportfs(char *arg, int verbose) - - static int can_test(void) - { -+ char buf[1024]; - int fd; - int n; -- char *setup = "nfsd 0.0.0.0 2147483647 -test-client-\n"; -+ - fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); -- if ( fd < 0) return 0; -- n = write(fd, setup, strlen(setup)); -+ if (fd < 0) -+ return 0; -+ -+ /* -+ * We introduce tolerance of 1 day to ensure that we use a -+ * LONG_MAX for the expiry timestamp before it is actually -+ * needed. To use LONG_MAX, the kernel code must have -+ * 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); -+ else -+ sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); -+ -+ n = write(fd, buf, strlen(buf)); - close(fd); - if (n < 0) - return 0; -+ - fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); -- if ( fd < 0) return 0; -+ if (fd < 0) -+ return 0; - close(fd); - return 1; - } -@@ -424,11 +444,15 @@ static int can_test(void) - static int test_export(char *path, int with_fsid) - { - char buf[1024]; -+ char *bp = buf; -+ int len = sizeof(buf); - int fd, n; - -- sprintf(buf, "-test-client- %s 3 %d 65534 65534 0\n", -- path, -- with_fsid ? NFSEXP_FSID : 0); -+ n = snprintf(buf, len, "-test-client- "); -+ bp += n; -+ len -= n; -+ qword_add(&bp, &len, path); -+ snprintf(bp, len, " 3 %d 65534 65534 0\n", with_fsid ? NFSEXP_FSID : 0); - fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); - if (fd < 0) - return 0; -@@ -596,7 +620,7 @@ export_d_read(const char *dname) - int fname_len; - - -- if (d->d_type != DT_UNKNOWN -+ if (d->d_type != DT_UNKNOWN - && d->d_type != DT_REG - && d->d_type != DT_LNK) - continue; -@@ -605,7 +629,7 @@ export_d_read(const char *dname) - - #define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) - namesz = strlen(d->d_name); -- if (!namesz -+ if (!namesz - || namesz < _EXT_EXPORT_SIZ + 1 - || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), - _EXT_EXPORT)) -@@ -619,7 +643,7 @@ export_d_read(const char *dname) - - export_read(fname); - } -- -+ - for (i = 0; i < n; i++) - free(namelist[i]); - free(namelist); -@@ -642,6 +666,9 @@ dumpopt(char c, char *fmt, ...) - static void - dump(int verbose, int export_format) - { -+ char buf[1024]; -+ char *bp; -+ int len; - nfs_export *exp; - struct exportent *ep; - int htype; -@@ -659,7 +686,15 @@ dump(int verbose, int export_format) - if (strlen(ep->e_path) > 14 && !export_format) - printf("%-14s\n\t\t%s", ep->e_path, hname); - else -- printf(((export_format)? "%s %s" : "%-14s\t%s"), ep->e_path, hname); -+ if (export_format) { -+ bp = buf; -+ len = sizeof(buf) - 1; -+ qword_add(&bp, &len, ep->e_path); -+ *bp = '\0'; -+ printf("%s %s", buf, hname); -+ } else { -+ printf("%-14s\t%s", ep->e_path, hname); -+ } - - if (!verbose && !export_format) { - printf("\n"); -@@ -697,8 +732,8 @@ dump(int verbose, int export_format) - if (ep->e_uuid) - c = dumpopt(c, "fsid=%s", ep->e_uuid); - if (ep->e_mountpoint) -- c = dumpopt(c, "mountpoint%s%s", -- ep->e_mountpoint[0]?"=":"", -+ c = dumpopt(c, "mountpoint%s%s", -+ ep->e_mountpoint[0]?"=":"", - ep->e_mountpoint); - if (ep->e_anonuid != 65534) - c = dumpopt(c, "anonuid=%d", ep->e_anonuid); -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 8ee478b..fdad153 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -54,6 +54,7 @@ - #include "err_util.h" - #include "gss_util.h" - #include "krb5_util.h" -+#include "nfslib.h" - - char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR; - char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE; -@@ -63,6 +64,7 @@ int use_memcache = 0; - int root_uses_machine_creds = 1; - unsigned int context_timeout = 0; - char *preferred_realm = NULL; -+int pipefds[2] = { -1, -1 }; - - void - sig_die(int signal) -@@ -187,8 +189,8 @@ main(int argc, char *argv[]) - if (gssd_check_mechs() != 0) - errx(1, "Problem with gssapi library"); - -- if (!fg && daemon(0, 0) < 0) -- errx(1, "fork"); -+ if (!fg) -+ mydaemon(0, 0, pipefds); - - signal(SIGINT, sig_die); - signal(SIGTERM, sig_die); -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index 86472a1..56a18d6 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -67,12 +67,14 @@ extern int use_memcache; - extern int root_uses_machine_creds; - extern unsigned int context_timeout; - extern char *preferred_realm; -+extern int pipefds[2]; - - TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; - - struct clnt_info { - TAILQ_ENTRY(clnt_info) list; - char *dirname; -+ char *pdir; - int dir_fd; - char *servicename; - char *servername; -diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c -index ccf7fe5..9970028 100644 ---- a/utils/gssd/gssd_main_loop.c -+++ b/utils/gssd/gssd_main_loop.c -@@ -53,6 +53,7 @@ - - #include "gssd.h" - #include "err_util.h" -+#include "nfslib.h" - - extern struct pollfd *pollarray; - extern unsigned long pollsize; -@@ -245,6 +246,9 @@ gssd_run() - /* Error msg is already printed */ - exit(1); - } -+ -+ /* release the parent after the initial dir scan */ -+ release_parent(pipefds); - } - gssd_poll(pollarray, pollsize); - } -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index b48d163..2a6ea97 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -256,6 +256,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername, - if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1) - goto fail; - close(fd); -+ fd = -1; - buf[nbytes] = '\0'; - - numfields = sscanf(buf,"RPC server: %127s\n" -@@ -322,6 +323,7 @@ destroy_client(struct clnt_info *clp) - if (clp->krb5_fd != -1) close(clp->krb5_fd); - if (clp->gssd_fd != -1) close(clp->gssd_fd); - free(clp->dirname); -+ free(clp->pdir); - free(clp->servicename); - free(clp->servername); - free(clp->protocol); -@@ -403,11 +405,10 @@ process_clnt_dir_files(struct clnt_info * clp) - return -1; - snprintf(info_file_name, sizeof(info_file_name), "%s/info", - clp->dirname); -- if ((clp->servicename == NULL) && -- read_service_info(info_file_name, &clp->servicename, -- &clp->servername, &clp->prog, &clp->vers, -- &clp->protocol, (struct sockaddr *) &clp->addr)) -- return -1; -+ if (clp->prog == 0) -+ read_service_info(info_file_name, &clp->servicename, -+ &clp->servername, &clp->prog, &clp->vers, -+ &clp->protocol, (struct sockaddr *) &clp->addr); - return 0; - } - -@@ -463,6 +464,9 @@ process_clnt_dir(char *dir, char *pdir) - if (!(clp = insert_new_clnt())) - goto fail_destroy_client; - -+ if (!(clp->pdir = strdup(pdir))) -+ goto fail_destroy_client; -+ - /* An extra for the '/', and an extra for the null */ - if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) { - goto fail_destroy_client; -@@ -527,7 +531,7 @@ update_old_clients(struct dirent **namelist, int size, char *pdir) - /* only compare entries in the global list that are from the - * same pipefs parent directory as "pdir" - */ -- if (strcmp(clp->dirname, pdir) != 0) continue; -+ if (strcmp(clp->pdir, pdir) != 0) continue; - - stillhere = 0; - for (i=0; i < size; i++) { -@@ -1040,7 +1044,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - return; - default: - /* Parent: just wait on child to exit and return */ -- wait(&err); -+ do { -+ pid = wait(&err); -+ } while(pid == -1 && errno != -ECHILD); -+ - if (WIFSIGNALED(err)) - printerr(0, "WARNING: forked child was killed with signal %d\n", - WTERMSIG(err)); -@@ -1320,11 +1327,14 @@ handle_gssd_upcall(struct clnt_info *clp) - } - } - -- if (strcmp(mech, "krb5") == 0) -+ if (strcmp(mech, "krb5") == 0 && clp->servername) - process_krb5_upcall(clp, uid, clp->gssd_fd, target, service); -- else -- printerr(0, "WARNING: handle_gssd_upcall: " -- "received unknown gss mech '%s'\n", mech); -+ else { -+ if (clp->servername) -+ printerr(0, "WARNING: handle_gssd_upcall: " -+ "received unknown gss mech '%s'\n", mech); -+ do_error_downcall(clp->gssd_fd, uid, -EACCES); -+ } - - out: - free(lbuf); -diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c -index 8aee3b2..0385725 100644 ---- a/utils/gssd/svcgssd.c -+++ b/utils/gssd/svcgssd.c -@@ -62,91 +62,7 @@ - #include "gss_util.h" - #include "err_util.h" - --/* -- * mydaemon creates a pipe between the partent and child -- * process. The parent process will wait until the -- * child dies or writes a '1' on the pipe signaling -- * that it started successfully. -- */ --int pipefds[2] = { -1, -1}; -- --static void --mydaemon(int nochdir, int noclose) --{ -- int pid, status, tempfd; -- -- if (pipe(pipefds) < 0) { -- printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n", -- errno, strerror(errno)); -- exit(1); -- } -- if ((pid = fork ()) < 0) { -- printerr(1, "mydaemon: fork() failed: errno %d (%s)\n", -- errno, strerror(errno)); -- exit(1); -- } -- -- if (pid != 0) { -- /* -- * Parent. Wait for status from child. -- */ -- close(pipefds[1]); -- if (read(pipefds[0], &status, 1) != 1) -- exit(1); -- exit (0); -- } -- /* Child. */ -- close(pipefds[0]); -- setsid (); -- if (nochdir == 0) { -- if (chdir ("/") == -1) { -- printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n", -- errno, strerror(errno)); -- exit(1); -- } -- } -- -- while (pipefds[1] <= 2) { -- pipefds[1] = dup(pipefds[1]); -- if (pipefds[1] < 0) { -- printerr(1, "mydaemon: dup() failed: errno %d (%s)\n", -- errno, strerror(errno)); -- exit(1); -- } -- } -- -- if (noclose == 0) { -- tempfd = open("/dev/null", O_RDWR); -- if (tempfd >= 0) { -- dup2(tempfd, 0); -- dup2(tempfd, 1); -- dup2(tempfd, 2); -- close(tempfd); -- } else { -- printerr(1, "mydaemon: can't open /dev/null: errno %d " -- "(%s)\n", errno, strerror(errno)); -- exit(1); -- } -- } -- -- return; --} -- --static void --release_parent(void) --{ -- int status; -- -- if (pipefds[1] > 0) { -- if (write(pipefds[1], &status, 1) != 1) { -- printerr(1, -- "WARN: writing to parent pipe failed: errno %d (%s)\n", -- errno, strerror(errno)); -- } -- close(pipefds[1]); -- pipefds[1] = -1; -- } --} -+static int pipefds[2] = { -1, -1 }; - - void - sig_die(int signal) -@@ -242,7 +158,7 @@ main(int argc, char *argv[]) - } - - if (!fg) -- mydaemon(0, 0); -+ mydaemon(0, 0, pipefds); - - signal(SIGINT, sig_die); - signal(SIGTERM, sig_die); -@@ -272,7 +188,7 @@ main(int argc, char *argv[]) - } - - if (!fg) -- release_parent(); -+ release_parent(pipefds); - - nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ - gssd_run(); -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index b6c6231..c02849b 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -157,9 +157,6 @@ static int nfsdopenone(struct idmap_client *); - static void nfsdreopen_one(struct idmap_client *); - static void nfsdreopen(void); - --void mydaemon(int, int); --void release_parent(void); -- - static int verbose = 0; - #define DEFAULT_IDMAP_CACHE_EXPIRY 600 /* seconds */ - static int cache_entry_expiration = 0; -@@ -167,6 +164,7 @@ static char pipefsdir[PATH_MAX]; - static char *nobodyuser, *nobodygroup; - static uid_t nobodyuid; - static gid_t nobodygid; -+static int pipefds[2] = { -1, -1 }; - - /* Used by conffile.c in libnfs.a */ - char *conf_path; -@@ -305,7 +303,7 @@ main(int argc, char **argv) - errx(1, "Unable to create name to user id mappings."); - - if (!fg) -- mydaemon(0, 0); -+ mydaemon(0, 0, pipefds); - - event_init(); - -@@ -382,7 +380,7 @@ main(int argc, char **argv) - if (nfsdret != 0 && fd == 0) - xlog_err("main: Neither NFS client nor NFSd found"); - -- release_parent(); -+ release_parent(pipefds); - - if (event_dispatch() < 0) - xlog_err("main: event_dispatch returns errno %d (%s)", -@@ -929,77 +927,3 @@ getfield(char **bpp, char *fld, size_t fldsz) - - return (0); - } --/* -- * mydaemon creates a pipe between the partent and child -- * process. The parent process will wait until the -- * child dies or writes a '1' on the pipe signaling -- * that it started successfully. -- */ --int pipefds[2] = { -1, -1}; -- --void --mydaemon(int nochdir, int noclose) --{ -- int pid, status, tempfd; -- -- if (pipe(pipefds) < 0) -- err(1, "mydaemon: pipe() failed: errno %d", errno); -- -- if ((pid = fork ()) < 0) -- err(1, "mydaemon: fork() failed: errno %d", errno); -- -- if (pid != 0) { -- /* -- * Parent. Wait for status from child. -- */ -- close(pipefds[1]); -- if (read(pipefds[0], &status, 1) != 1) -- exit(1); -- exit (0); -- } -- /* Child. */ -- close(pipefds[0]); -- setsid (); -- if (nochdir == 0) { -- if (chdir ("/") == -1) -- err(1, "mydaemon: chdir() failed: errno %d", errno); -- } -- -- while (pipefds[1] <= 2) { -- pipefds[1] = dup(pipefds[1]); -- if (pipefds[1] < 0) -- err(1, "mydaemon: dup() failed: errno %d", errno); -- } -- -- if (noclose == 0) { -- tempfd = open("/dev/null", O_RDWR); -- if (tempfd < 0) -- tempfd = open("/", O_RDONLY); -- if (tempfd >= 0) { -- dup2(tempfd, 0); -- dup2(tempfd, 1); -- dup2(tempfd, 2); -- close(tempfd); -- } else { -- err(1, "mydaemon: can't open /dev/null: errno %d", -- errno); -- exit(1); -- } -- } -- -- return; --} --void --release_parent(void) --{ -- int status; -- -- if (pipefds[1] > 0) { -- if (write(pipefds[1], &status, 1) != 1) { -- err(1, "Writing to parent pipe failed: errno %d (%s)\n", -- errno, strerror(errno)); -- } -- close(pipefds[1]); -- pipefds[1] = -1; -- } --} -diff --git a/utils/mount/network.c b/utils/mount/network.c -index e8e55a5..2fdd2c0 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -92,6 +92,9 @@ static const char *nfs_version_opttbl[] = { - "v4", - "vers", - "nfsvers", -+ "v4.0", -+ "v4.1", -+ "v4.2", - NULL, - }; - -@@ -1242,6 +1245,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) - *version = tmp; - return 1; - } -+ nfs_error(_("%s: parsing error on 'vers=' option\n"), -+ progname); - return 0; - case PO_NOT_FOUND: - nfs_error(_("%s: parsing error on 'vers=' option\n"), -@@ -1259,6 +1264,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) - *version = tmp; - return 1; - } -+ nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), -+ progname); - return 0; - case PO_NOT_FOUND: - nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), -@@ -1269,6 +1276,11 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) - progname); - return 0; - } -+ case 5: /* v4.0 */ -+ case 6: /* v4.1 */ -+ case 7: /* v4.2 */ -+ *version = 4; -+ return 1; - } - - /* -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index 67031b5..ecc5f64 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -856,6 +856,26 @@ In the presence of multiple client network interfaces, - special routing policies, - or atypical network topologies, - the exact address to use for callbacks may be nontrivial to determine. -+.TP 1.5i -+.BR migration " / " nomigration -+Selects whether the client uses an identification string that is compatible -+with NFSv4 Transparent State Migration (TSM). -+If the mounted server supports NFSv4 migration with TSM, specify the -+.B migration -+option. -+.IP -+Some server features misbehave in the face of a migration-compatible -+identification string. -+The -+.B nomigration -+option retains the use of a traditional client indentification string -+which is compatible with legacy NFS servers. -+This is also the behavior if neither option is specified. -+A client's open and lock state cannot be migrated transparently -+when it identifies itself via a traditional identification string. -+.IP -+This mount option has no effect with NFSv4 minor versions newer than zero, -+which always use TSM-compatible client identification strings. - .SH nfs4 FILE SYSTEM TYPE - The - .BR nfs4 -@@ -1227,6 +1247,65 @@ If absolute cache coherence among clients is required, - applications should use file locking. Alternatively, applications - can also open their files with the O_DIRECT flag - to disable data caching entirely. -+.SS "File timestamp maintainence" -+NFS servers are responsible for managing file and directory timestamps -+.RB ( atime , -+.BR ctime ", and" -+.BR mtime ). -+When a file is accessed or updated on an NFS server, -+the file's timestamps are updated just like they would be on a filesystem -+local to an application. -+.P -+NFS clients cache file attributes, including timestamps. -+A file's timestamps are updated on NFS clients when its attributes -+are retrieved from the NFS server. -+Thus there may be some delay before timestamp updates -+on an NFS server appear to applications on NFS clients. -+.P -+To comply with the POSIX filesystem standard, the Linux NFS client -+relies on NFS servers to keep a file's -+.B mtime -+and -+.B ctime -+timestamps properly up to date. -+It does this by flushing local data changes to the server -+before reporting -+.B mtime -+to applications via system calls such as -+.BR stat (2). -+.P -+The Linux client handles -+.B atime -+updates more loosely, however. -+NFS clients maintain good performance by caching data, -+but that means that application reads, which normally update -+.BR atime , -+are not reflected to the server where a file's -+.B atime -+is actually maintained. -+.P -+Because of this caching behavior, -+the Linux NFS client does not support generic atime-related mount options. -+See -+.BR mount (8) -+for details on these options. -+.P -+In particular, the -+.BR atime / noatime , -+.BR diratime / nodiratime , -+.BR relatime / norelatime , -+and -+.BR strictatime / nostrictatime -+mount options have no effect on NFS mounts. -+.P -+.I /proc/mounts -+may report that the -+.B relatime -+mount option is set on NFS mounts, but in fact the -+.B atime -+semantics are always as described here, and are not like -+.B relatime -+semantics. - .SS "Directory entry caching" - The Linux NFS client caches the result of all NFS LOOKUP requests. - If the requested directory entry exists on the server, -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index e04b86e..ca35de2 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -266,6 +266,27 @@ static int get_uuid(const char *val, size_t uuidlen, char *u) - return 1; - } - -+ -+/* -+ * Don't ask libblkid for these filesystems. Note that BTRF is ignored, because -+ * we generate the identifier from statfs->f_fsid. The rest are network or -+ * pseudo filesystems. (See for the basic IDs.) -+ */ -+static const long int nonblkid_filesystems[] = { -+ 0x2fc12fc1, /* ZFS_SUPER_MAGIC */ -+ 0x9123683E, /* BTRFS_SUPER_MAGIC */ -+ 0xFF534D42, /* CIFS_MAGIC_NUMBER */ -+ 0x1373, /* DEVFS_SUPER_MAGIC */ -+ 0x73757245, /* CODA_SUPER_MAGIC */ -+ 0x564C, /* NCP_SUPER_MAGIC */ -+ 0x6969, /* NFS_SUPER_MAGIC */ -+ 0x9FA0, /* PROC_SUPER_MAGIC */ -+ 0x62656572, /* SYSFS_MAGIC */ -+ 0x517B, /* SMB_SUPER_MAGIC */ -+ 0x01021994, /* TMPFS_SUPER_MAGIC */ -+ 0 /* last */ -+}; -+ - static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) - { - /* get a uuid for the filesystem found at 'path'. -@@ -297,12 +318,23 @@ static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) - */ - struct statfs64 st; - char fsid_val[17]; -- const char *blkid_val; -+ const char *blkid_val = NULL; - const char *val; -+ int rc; - -- blkid_val = get_uuid_blkdev(path); -+ rc = statfs64(path, &st); -+ -+ if (type == 0 && rc == 0) { -+ const long int *bad; -+ for (bad = nonblkid_filesystems; *bad; bad++) { -+ if (*bad == st.f_type) -+ break; -+ } -+ if (*bad == 0) -+ blkid_val = get_uuid_blkdev(path); -+ } - -- if (statfs64(path, &st) == 0 && -+ if (rc == 0 && - (st.f_fsid.__val[0] || st.f_fsid.__val[1])) - snprintf(fsid_val, 17, "%08x%08x", - st.f_fsid.__val[0], st.f_fsid.__val[1]); -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 6db92f0..a9d77ab 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -99,7 +99,7 @@ main(int argc, char **argv) - char *p, *progname, *port; - char *haddr = NULL; - int socket_up = 0; -- int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */ -+ int minorvers[NFS4_MAXMINOR + 1] = {0}; - unsigned int versbits = NFSCTL_VERDEFAULT; - unsigned int protobits = NFSCTL_ALLBITS; - unsigned int proto4 = 0; -@@ -164,7 +164,7 @@ main(int argc, char **argv) - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- NFSCTL_VERUNSET(minorvers, i); -+ minorvers[i] = -1; - break; - } - case 3: -@@ -185,7 +185,7 @@ main(int argc, char **argv) - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- NFSCTL_VERSET(minorvers, i); -+ minorvers[i] = 1; - break; - } - case 3: -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 8b85846..1b50aba 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits, - } - - void --nfssvc_setvers(unsigned int ctlbits, int minorvers) -+nfssvc_setvers(unsigned int ctlbits, int minorvers[]) - { - int fd, n, off; - char *ptr; -@@ -281,9 +281,9 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers) - return; - - for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { -- if (NFSCTL_VERISSET(minorvers, n)) -+ if (minorvers[n] == 1) - off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); -- else -+ else if (minorvers[n] == -1) - off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); - } - for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { -diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h -index 08de0fe..2bbd3d3 100644 ---- a/utils/nfsd/nfssvc.h -+++ b/utils/nfsd/nfssvc.h -@@ -24,5 +24,5 @@ void nfssvc_mount_nfsdfs(char *progname); - int nfssvc_inuse(void); - int nfssvc_set_sockets(const int family, const unsigned int protobits, - const char *host, const char *port); --void nfssvc_setvers(unsigned int ctlbits, int minorvers4); -+void nfssvc_setvers(unsigned int ctlbits, int minorvers4[]); - int nfssvc_threads(unsigned short port, int nrservs); diff --git a/nfs-utils-1.3.2.rc4.patch b/nfs-utils-1.3.2.rc4.patch deleted file mode 100644 index 9a629c6..0000000 --- a/nfs-utils-1.3.2.rc4.patch +++ /dev/null @@ -1,3463 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index 5824adc..4a2edc6 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -2,41 +2,13 @@ - - AUTOMAKE_OPTIONS = foreign - --SUBDIRS = tools support utils linux-nfs tests -+SUBDIRS = tools support utils linux-nfs tests systemd - - MAINTAINERCLEANFILES = Makefile.in - - EXTRA_DIST = \ - autogen.sh \ - \ -- debian/changelog \ -- debian/control \ -- debian/copyright \ -- debian/etc.exports \ -- debian/idmapd.conf \ -- debian/nfs-common.conffiles \ -- debian/nfs-common.default \ -- debian/nfs-common.dirs \ -- debian/nfs-common.files \ -- debian/nfs-common.init \ -- debian/nfs-common.install \ -- debian/nfs-common.postinst \ -- debian/nfs-common.postrm \ -- debian/nfs-common.prerm \ -- debian/nfs-kernel-server.NEWS \ -- debian/nfs-kernel-server.conffiles \ -- debian/nfs-kernel-server.default \ -- debian/nfs-kernel-server.dirs \ -- debian/nfs-kernel-server.init \ -- debian/nfs-kernel-server.postinst \ -- debian/nfs-kernel-server.postrm \ -- debian/nfs-kernel-server.prerm \ -- debian/nhfsstone.dirs \ -- debian/nhfsstone.files \ -- debian/nhfsstone.postinst \ -- debian/nhfsstone.prerm \ -- debian/rules \ -- \ - aclocal/bsdsignals.m4 \ - aclocal/nfs-utils.m4 \ - aclocal/kerberos5.m4 \ -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index b823364..ebc1bea 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -2,61 +2,18 @@ dnl Checks for TI-RPC library and headers - dnl - AC_DEFUN([AC_LIBTIRPC], [ - -- AC_ARG_WITH([tirpcinclude], -- [AC_HELP_STRING([--with-tirpcinclude=DIR], -- [use TI-RPC headers in DIR])], -- [tirpc_header_dir=$withval], -- [tirpc_header_dir=/usr/include/tirpc]) -- -- dnl if --enable-tirpc was specifed, the following components -- dnl must be present, and we set up HAVE_ macros for them. -- -- if test "$enable_tirpc" != "no"; then -- -- dnl look for the library -- AC_CHECK_LIB([tirpc], [clnt_tli_create], [:], -- [if test "$enable_tirpc" = "yes"; then -- AC_MSG_ERROR([libtirpc not found.]) -- else -- AC_MSG_WARN([libtirpc not found. TIRPC disabled!]) -- enable_tirpc="no" -- fi]) -- fi -- -- if test "$enable_tirpc" != "no"; then -- -- dnl Check if library contains authgss_free_private_data -- AC_CHECK_LIB([tirpc], [authgss_free_private_data], [have_free_private_data=yes], -- [have_free_private_data=no]) -- fi -- -- if test "$enable_tirpc" != "no"; then -- dnl also must have the headers installed where we expect -- dnl look for headers; add -I compiler option if found -- AC_CHECK_HEADERS([${tirpc_header_dir}/netconfig.h], -- AC_SUBST([AM_CPPFLAGS], ["-I${tirpc_header_dir}"]), -- [if test "$enable_tirpc" = "yes"; then -- AC_MSG_ERROR([libtirpc headers not found.]) -- else -- AC_MSG_WARN([libtirpc headers not found. TIRPC disabled!]) -- enable_tirpc="no" -- fi]) -- -- fi -- -- dnl now set $LIBTIRPC accordingly -- if test "$enable_tirpc" != "no"; then -- AC_DEFINE([HAVE_LIBTIRPC], 1, -- [Define to 1 if you have and wish to use libtirpc.]) -- LIBTIRPC="-ltirpc" -- if test "$have_free_private_data" = "yes"; then -- AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1, -- [Define to 1 if your rpcsec library provides authgss_free_private_data,]) -- fi -- else -- LIBTIRPC="" -- fi -- -+ PKG_PROG_PKG_CONFIG([0.9.0]) -+ AS_IF( -+ [test "$enable_tirpc" != "no"], -+ [PKG_CHECK_MODULES([TIRPC], [libtirpc >= 0.2.4], -+ [LIBTIRPC="${TIRPC_LIBS}" -+ AM_CPPFLAGS="${AM_CPPFLAGS} ${TIRPC_CFLAGS}" -+ AC_DEFINE([HAVE_LIBTIRPC], [1], -+ [Define to 1 if you have and wish to use libtirpc.])], -+ [AS_IF([test "$enable_tirpc" != "no"], [AC_MSG_ERROR([libtirpc not found.])], -+ [LIBTIRPC=""])])]) -+ -+ AC_SUBST([AM_CPPFLAGS]) - AC_SUBST(LIBTIRPC) - - ])dnl -diff --git a/configure.ac b/configure.ac -index 59fd14d..a8b1fc3 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -55,6 +55,16 @@ AC_ARG_WITH(start-statd, - ) - AC_SUBST(startstatd) - AC_DEFINE_UNQUOTED(START_STATD, "$startstatd", [Define this to a script which can start statd on mount]) -+unitdir=/usr/lib/systemd/system -+AC_ARG_WITH(systemd, -+ [AC_HELP_STRING([--with-systemd@<:@=unit-dir-path@:>@], -+ [install systemd unit files @<:@Default: no, and path defaults to /usr/lib/systemd/system if not given@:>@])], -+ test "$withval" = "no" && use_systemd=0 || unitdir=$withval use_systemd=1 -+ use_systemd=0 -+ ) -+ AM_CONDITIONAL(INSTALL_SYSTEMD, [test "$use_systemd" = 1]) -+ AC_SUBST(unitdir) -+ - AC_ARG_ENABLE(nfsv4, - [AC_HELP_STRING([--enable-nfsv4], - [enable support for NFSv4 @<:@default=yes@:>@])], -@@ -108,10 +118,8 @@ AC_ARG_ENABLE(svcgss, - [enable building svcgssd for rpcsec_gss server support @<:@default=yes@:>@])], - enable_svcgss=$enableval, - enable_svcgss=yes) -- if test "$enable_gss" = yes; then -- if "enable_svcgss" = yes; then -- SVCGSSD=svcgssd -- fi -+ if test "$enable_gss" = yes -a "$enable_svcgss" = yes; then -+ SVCGSSD=svcgssd - else - enable_svcgss= - SVCGSSD= -@@ -518,6 +526,7 @@ AC_CONFIG_FILES([ - utils/showmount/Makefile - utils/statd/Makefile - utils/osd_login/Makefile -+ systemd/Makefile - tests/Makefile - tests/nsm_client/Makefile]) - AC_OUTPUT -diff --git a/support/export/client.c b/support/export/client.c -index f85e11c..95156f0 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -277,7 +277,7 @@ client_lookup(char *hname, int canonical) - if (htype == MCL_FQDN && !canonical) { - ai = host_addrinfo(hname); - if (!ai) { -- xlog(L_ERROR, "Failed to resolve %s", hname); -+ xlog(L_WARNING, "Failed to resolve %s", hname); - goto out; - } - hname = ai->ai_canonname; -diff --git a/support/export/export.c b/support/export/export.c -index 6b1d045..e1bebce 100644 ---- a/support/export/export.c -+++ b/support/export/export.c -@@ -69,22 +69,30 @@ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep) - * export_read - read entries from /etc/exports - * @fname: name of file to read from - * -+ * Returns number of read entries. - */ --void -+int - export_read(char *fname) - { - struct exportent *eep; - nfs_export *exp; - -+ int volumes = 0; -+ - setexportent(fname, "r"); - while ((eep = getexportent(0,1)) != NULL) { - exp = export_lookup(eep->e_hostname, eep->e_path, 0); -- if (!exp) -- export_create(eep, 0); -+ if (!exp) { -+ if (export_create(eep, 0)) -+ /* possible complaints already logged */ -+ volumes++; -+ } - else - warn_duplicated_exports(exp, eep); - } - endexportent(); -+ -+ return volumes; - } - - /** -diff --git a/support/export/hostname.c b/support/export/hostname.c -index d9153e1..169baa5 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -177,11 +177,11 @@ host_addrinfo(const char *hostname) - case 0: - return ai; - case EAI_SYSTEM: -- xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m", -+ xlog(D_PARSE, "%s: failed to resolve %s: (%d) %m", - __func__, hostname, errno); - break; - default: -- xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ xlog(D_PARSE, "%s: failed to resolve %s: %s", - __func__, hostname, gai_strerror(error)); - break; - } -diff --git a/support/include/Makefile.am b/support/include/Makefile.am -index 4b33ee9..5c80c8b 100644 ---- a/support/include/Makefile.am -+++ b/support/include/Makefile.am -@@ -3,6 +3,7 @@ - SUBDIRS = nfs rpcsvc sys - - noinst_HEADERS = \ -+ cld.h \ - exportfs.h \ - ha-callout.h \ - misc.h \ -@@ -10,9 +11,13 @@ noinst_HEADERS = \ - nfs_paths.h \ - nfslib.h \ - nfsrpc.h \ -+ nls.h \ - nsm.h \ -+ pseudoflavors.h \ - rpcmisc.h \ -+ sockaddr.h \ - tcpwrapper.h \ -+ v4root.h \ - xio.h \ - xlog.h \ - xmalloc.h \ -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 9021fae..4cac203 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -10,6 +10,7 @@ - #define EXPORTFS_H - - #include -+#include - - #include "sockaddr.h" - #include "nfslib.h" -@@ -133,7 +134,7 @@ struct addrinfo * client_resolve(const struct sockaddr *sap); - int client_member(const char *client, - const char *name); - --void export_read(char *fname); -+int export_read(char *fname); - void export_reset(nfs_export *); - nfs_export * export_lookup(char *hname, char *path, int caconical); - nfs_export * export_find(const struct addrinfo *ai, -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index ce4b14b..c5dc6f8 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -152,11 +152,6 @@ struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path); - struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin, - const char *path, int const size); - --void qword_print(FILE *f, char *str); --void qword_printhex(FILE *f, char *str, int slen); --void qword_printint(FILE *f, int num); --int qword_eol(FILE *f); --int readline(int fd, char **buf, int *lenp); - int qword_get(char **bpp, char *dest, int bufsize); - int qword_get_int(char **bpp, int *anint); - void cache_flush(int force); -@@ -167,13 +162,12 @@ void qword_addint(char **bpp, int *lp, int n); - void qword_adduint(char **bpp, int *lp, unsigned int n); - void qword_addeol(char **bpp, int *lp); - int qword_get_uint(char **bpp, unsigned int *anint); --void qword_printuint(FILE *f, unsigned int num); --void qword_printtimefrom(FILE *f, unsigned int num); - - void closeall(int min); - - int svctcp_socket (u_long __number, int __reuse); - int svcudp_socket (u_long __number); -+int svcsock_nonblock (int __sock); - - /* Misc shared code prototypes */ - size_t strlcat(char *, const char *, size_t); -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index 1bfae7a..fbbdb6a 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -23,6 +23,7 @@ - #ifndef __NFS_UTILS_NFSRPC_H - #define __NFS_UTILS_NFSRPC_H - -+#include - #include - #include - -diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c -index 61e07a8..42e2502 100644 ---- a/support/nfs/cacheio.c -+++ b/support/nfs/cacheio.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -120,74 +121,6 @@ void qword_addeol(char **bpp, int *lp) - (*lp)--; - } - --static char qword_buf[8192]; --void qword_print(FILE *f, char *str) --{ -- char *bp = qword_buf; -- int len = sizeof(qword_buf); -- qword_add(&bp, &len, str); -- if (fwrite(qword_buf, bp-qword_buf, 1, f) != 1) { -- xlog_warn("qword_print: fwrite failed: errno %d (%s)", -- errno, strerror(errno)); -- } --} -- --void qword_printhex(FILE *f, char *str, int slen) --{ -- char *bp = qword_buf; -- int len = sizeof(qword_buf); -- qword_addhex(&bp, &len, str, slen); -- if (fwrite(qword_buf, bp-qword_buf, 1, f) != 1) { -- xlog_warn("qword_printhex: fwrite failed: errno %d (%s)", -- errno, strerror(errno)); -- } --} -- --void qword_printint(FILE *f, int num) --{ -- fprintf(f, "%d ", num); --} -- --void qword_printuint(FILE *f, unsigned int num) --{ -- fprintf(f, "%u ", num); --} -- --void qword_printtimefrom(FILE *f, unsigned int num) --{ -- fprintf(f, "%lu ", time(0) + num); --} -- --int qword_eol(FILE *f) --{ -- int err; -- -- err = fprintf(f,"\n"); -- if (err < 0) { -- xlog_warn("qword_eol: fprintf failed: errno %d (%s)", -- errno, strerror(errno)); -- } else { -- err = fflush(f); -- if (err) { -- xlog_warn("qword_eol: fflush failed: errno %d (%s)", -- errno, strerror(errno)); -- } -- } -- /* -- * We must send one line (and one line only) in a single write -- * call. In case of a write error, libc may accumulate the -- * unwritten data and try to write it again later, resulting in a -- * multi-line write. So we must explicitly ask it to throw away -- * any such cached data. But we return any original error -- * indication to the caller. -- */ -- __fpurge(f); -- fflush(f); -- return err; --} -- -- -- - #define isodigit(c) (isdigit(c) && c <= '7') - int qword_get(char **bpp, char *dest, int bufsize) - { -@@ -265,48 +198,6 @@ int qword_get_uint(char **bpp, unsigned int *anint) - return 0; - } - --#define READLINE_BUFFER_INCREMENT 2048 -- --int readline(int fd, char **buf, int *lenp) --{ -- /* read a line into *buf, which is malloced *len long -- * realloc if needed until we find a \n -- * nul out the \n and return -- * 0 on eof, 1 on success -- */ -- int len; -- -- if (*lenp == 0) { -- char *b = malloc(READLINE_BUFFER_INCREMENT); -- if (b == NULL) -- return 0; -- *buf = b; -- *lenp = READLINE_BUFFER_INCREMENT; -- } -- len = read(fd, *buf, *lenp); -- if (len <= 0) -- return 0; -- while ((*buf)[len-1] != '\n') { -- /* now the less common case. There was no newline, -- * so we have to keep reading after re-alloc -- */ -- char *new; -- int nl; -- *lenp += READLINE_BUFFER_INCREMENT; -- new = realloc(*buf, *lenp); -- if (new == NULL) -- return 0; -- *buf = new; -- nl = read(fd, *buf + len, *lenp - len); -- if (nl <= 0) -- return 0; -- len += nl; -- } -- (*buf)[len-1] = '\0'; -- return 1; --} -- -- - /* Check if we should use the new caching interface - * This succeeds iff the "nfsd" filesystem is mounted on - * /proc/fs/nfs -diff --git a/support/nfs/nfsexport.c b/support/nfs/nfsexport.c -index f129fd2..afd7c90 100644 ---- a/support/nfs/nfsexport.c -+++ b/support/nfs/nfsexport.c -@@ -18,6 +18,7 @@ - #include - - #include "nfslib.h" -+#include "misc.h" - - /* if /proc/net/rpc/... exists, then - * write to it, as that interface is more stable. -@@ -32,62 +33,72 @@ - static int - exp_unexp(struct nfsctl_export *exp, int export) - { -- FILE *f; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; - struct stat stb; - __u32 fsid; - char fsidstr[8]; - __u16 dev; - __u32 inode; -- int err; -+ int err = 0, f, blen; - -+ f = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); -+ if (f < 0) return -1; - -- f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); -- if (f == NULL) return -1; -- qword_print(f, exp->ex_client); -- qword_print(f, exp->ex_path); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->ex_client); -+ qword_add(&bp, &blen, exp->ex_path); - if (export) { -- qword_printint(f, 0x7fffffff); -- qword_printint(f, exp->ex_flags); -- qword_printint(f, exp->ex_anon_uid); -- qword_printint(f, exp->ex_anon_gid); -- qword_printint(f, exp->ex_dev); -+ qword_addint(&bp, &blen, 0x7fffffff); -+ qword_addint(&bp, &blen, exp->ex_flags); -+ qword_addint(&bp, &blen, exp->ex_anon_uid); -+ qword_addint(&bp, &blen, exp->ex_anon_gid); -+ qword_addint(&bp, &blen, exp->ex_dev); - } else -- qword_printint(f, 1); -- -- err = qword_eol(f); -- fclose(f); -+ qword_addint(&bp, &blen, 1); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ err = -1; -+ close(f); - - if (stat(exp->ex_path, &stb) != 0) - return -1; -- f = fopen("/proc/net/rpc/nfsd.fh/channel", "w"); -- if (f==NULL) return -1; -+ -+ f = open("/proc/net/rpc/nfsd.fh/channel", O_WRONLY); -+ if (f < 0) return -1; - if (exp->ex_flags & NFSEXP_FSID) { -- qword_print(f,exp->ex_client); -- qword_printint(f,1); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->ex_client); -+ qword_addint(&bp, &blen, 1); - fsid = exp->ex_dev; -- qword_printhex(f, (char*)&fsid, 4); -+ qword_addhex(&bp, &blen, (char*)&fsid, 4); - if (export) { -- qword_printint(f, 0x7fffffff); -- qword_print(f, exp->ex_path); -+ qword_addint(&bp, &blen, 0x7fffffff); -+ qword_add(&bp, &blen, exp->ex_path); - } else -- qword_printint(f, 1); -- -- err = qword_eol(f) || err; -+ qword_addint(&bp, &blen, 1); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ err = -1; - } -- qword_print(f,exp->ex_client); -- qword_printint(f,0); -+ -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->ex_client); -+ qword_addint(&bp, &blen, 0); - dev = htons(major(stb.st_dev)); memcpy(fsidstr, &dev, 2); - dev = htons(minor(stb.st_dev)); memcpy(fsidstr+2, &dev, 2); - inode = stb.st_ino; memcpy(fsidstr+4, &inode, 4); - -- qword_printhex(f, fsidstr, 8); -+ qword_addhex(&bp, &blen, fsidstr, 8); - if (export) { -- qword_printint(f, 0x7fffffff); -- qword_print(f, exp->ex_path); -+ qword_addint(&bp, &blen, 0x7fffffff); -+ qword_add(&bp, &blen, exp->ex_path); - } else -- qword_printint(f, 1); -- err = qword_eol(f) || err; -- fclose(f); -+ qword_addint(&bp, &blen, 1); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ err = -1; -+ close(f); -+ - return err; - } - -diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c -index 64c98ff..ae2c0a6 100644 ---- a/support/nfs/rpcmisc.c -+++ b/support/nfs/rpcmisc.c -@@ -104,7 +104,7 @@ makesock(int port, int proto) - return -1; - } - -- return sock; -+ return svcsock_nonblock(sock); - } - - void -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index a706f87..5cb5ff6 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -49,6 +49,8 @@ - - #ifdef HAVE_LIBTIRPC - -+#include -+ - #define SVC_CREATE_XPRT_CACHE_SIZE (8) - static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; - -@@ -277,6 +279,12 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - "(%s, %u, %s)", name, version, nconf->nc_netid); - return 0; - } -+ if (svcsock_nonblock(xprt->xp_fd) < 0) { -+ /* close() already done by svcsock_nonblock() */ -+ xprt->xp_fd = RPC_ANYFD; -+ SVC_DESTROY(xprt); -+ return 0; -+ } - - if (!svc_reg(xprt, program, version, dispatch, nconf)) { - /* svc_reg(3) destroys @xprt in this case */ -@@ -332,6 +340,7 @@ svc_create_nconf_fixed_port(const char *name, const rpcprog_t program, - int fd; - - fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); -+ fd = svcsock_nonblock(fd); - if (fd == -1) - goto out_free; - -@@ -394,6 +403,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, - const struct sigaction create_sigaction = { - .sa_handler = SIG_IGN, - }; -+ int maxrec = RPC_MAXDATASIZE; - unsigned int visible, up, servport; - struct netconfig *nconf; - void *handlep; -@@ -405,6 +415,20 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, - */ - (void)sigaction(SIGPIPE, &create_sigaction, NULL); - -+ /* -+ * Setting MAXREC also enables non-blocking mode for tcp connections. -+ * This avoids DOS attacks by a client sending many requests but never -+ * reading the reply: -+ * - if a second request already is present for reading in the socket, -+ * after the first request just was read, libtirpc will break the -+ * connection. Thus an attacker can't simply send requests as fast as -+ * he can without waiting for the response. -+ * - if the write buffer of the socket is full, the next write() will -+ * fail with EAGAIN. libtirpc will retry the write in a loop for max. -+ * 2 seconds. If write still fails, the connection will be closed. -+ */ -+ rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); -+ - handlep = setnetconfig(); - if (handlep == NULL) { - xlog(L_ERROR, "Failed to access local netconfig database: %s", -diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c -index 74273b9..99321e7 100644 ---- a/support/nfs/svc_socket.c -+++ b/support/nfs/svc_socket.c -@@ -76,6 +76,39 @@ int getservport(u_long number, const char *proto) - return 0; - } - -+int -+svcsock_nonblock(int sock) -+{ -+ int flags; -+ -+ if (sock < 0) -+ return sock; -+ -+ /* This socket might be shared among multiple processes -+ * if mountd is run multi-threaded. So it is safest to -+ * make it non-blocking, else all threads might wake -+ * one will get the data, and the others will block -+ * indefinitely. -+ * In all cases, transaction on this socket are atomic -+ * (accept for TCP, packet-read and packet-write for UDP) -+ * so O_NONBLOCK will not confuse unprepared code causing -+ * it to corrupt messages. -+ * It generally safest to have O_NONBLOCK when doing an accept -+ * as if we get a RST after the SYN and before accept runs, -+ * we can block despite being told there was an acceptable -+ * connection. -+ */ -+ if ((flags = fcntl(sock, F_GETFL)) < 0) -+ perror(_("svc_socket: can't get socket flags")); -+ else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -+ perror(_("svc_socket: can't set socket flags")); -+ else -+ return sock; -+ -+ (void) __close(sock); -+ return -1; -+} -+ - static int - svc_socket (u_long number, int type, int protocol, int reuse) - { -@@ -113,38 +146,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - sock = -1; - } - -- if (sock >= 0) -- { -- /* This socket might be shared among multiple processes -- * if mountd is run multi-threaded. So it is safest to -- * make it non-blocking, else all threads might wake -- * one will get the data, and the others will block -- * indefinitely. -- * In all cases, transaction on this socket are atomic -- * (accept for TCP, packet-read and packet-write for UDP) -- * so O_NONBLOCK will not confuse unprepared code causing -- * it to corrupt messages. -- * It generally safest to have O_NONBLOCK when doing an accept -- * as if we get a RST after the SYN and before accept runs, -- * we can block despite being told there was an acceptable -- * connection. -- */ -- int flags; -- if ((flags = fcntl(sock, F_GETFL)) < 0) -- { -- perror (_("svc_socket: can't get socket flags")); -- (void) __close (sock); -- sock = -1; -- } -- else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -- { -- perror (_("svc_socket: can't set socket flags")); -- (void) __close (sock); -- sock = -1; -- } -- } -- -- return sock; -+ return svcsock_nonblock(sock); - } - - /* -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -new file mode 100644 -index 0000000..16cf5e6 ---- /dev/null -+++ b/systemd/Makefile.am -@@ -0,0 +1,32 @@ -+## Process this file with automake to produce Makefile.in -+ -+MAINTAINERCLEANFILES = Makefile.in -+ -+unit_files = \ -+ nfs-blkmap.target \ -+ nfs-client.target \ -+ \ -+ auth-rpcgss-module.service \ -+ nfs-blkmap.service \ -+ nfs-config.service \ -+ nfs-idmapd.service \ -+ nfs-mountd.service \ -+ nfs-server.service \ -+ nfs-utils.service \ -+ rpc-gssd.service \ -+ rpc-statd-notify.service \ -+ rpc-statd.service \ -+ rpc-svcgssd.service \ -+ \ -+ proc-fs-nfsd.mount \ -+ var-lib-nfs-rpc_pipefs.mount -+ -+EXTRA_DIST = $(unit_files) -+ -+unit_dir = /usr/lib/systemd/system -+ -+if INSTALL_SYSTEMD -+install-data-hook: $(unit_files) -+ mkdir -p $(DESTDIR)/$(unitdir) -+ cp $(unit_files) $(DESTDIR)/$(unitdir) -+endif -diff --git a/systemd/auth-rpcgss-module.service b/systemd/auth-rpcgss-module.service -index 3fc2f4a..0355e13 100644 ---- a/systemd/auth-rpcgss-module.service -+++ b/systemd/auth-rpcgss-module.service -@@ -6,7 +6,8 @@ - # unit will fail. But that's OK.) - [Unit] - Description=Kernel Module supporting RPCSEC_GSS --Before=gssproxy.service rpc-svcgssd.service -+Before=gssproxy.service rpc-svcgssd.service rpc-gssd.service -+Wants=gssproxy.service rpc-svcgssd.service rpc-gssd.service - ConditionPathExists=/etc/krb5.keytab - - [Service] -diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service -index 68cc9e9..f470e3d 100644 ---- a/systemd/nfs-blkmap.service -+++ b/systemd/nfs-blkmap.service -@@ -13,4 +13,4 @@ PartOf=nfs-utils.service - [Service] - Type=forking - PIDFile=/var/run/blkmapd.pid --ExecStart=/usr/sbin/blkmapd -+ExecStart=/usr/sbin/blkmapd $BLKMAPDARGS -diff --git a/systemd/nfs-client.target b/systemd/nfs-client.target -index 474f5e9..9b792a3 100644 ---- a/systemd/nfs-client.target -+++ b/systemd/nfs-client.target -@@ -5,9 +5,12 @@ Wants=remote-fs-pre.target - - # Note: we don't "Wants=rpc-statd.service" as "mount.nfs" will arrange to - # start that on demand if needed. --Wants=rpc-gssd.service rpc-svcgssd.service auth-rpcgss-module.service - Wants=nfs-blkmap.service rpc-statd-notify.service --Before=rpc-gssd.service rpc-svcgssd.service nfs-blkmap.service -+After=nfs-blkmap.service -+ -+# GSS services dependencies and ordering -+Wants=auth-rpcgss-module.service -+After=rpc-gssd.service rpc-svcgssd.service gssproxy.service - - [Install] - WantedBy=multi-user.target -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 1048c5c..8010aad 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -2,15 +2,17 @@ - Description=NFS server and services - Requires= network.target proc-fs-nfsd.mount rpcbind.target - Requires= nfs-mountd.service --Wants=rpc-statd.service nfs-idmapd.service auth-rpcgss-module.service --Wants=rpc-gssd.service gssproxy.service rpc-svcgssd.service -+Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service - - After= network.target proc-fs-nfsd.mount rpcbind.target nfs-mountd.service - After= nfs-idmapd.service rpc-statd.service --After= rpc-gssd.service gssproxy.service rpc-svcgssd.service - Before= rpc-statd-notify.service - -+# GSS services dependencies and ordering -+Wants=auth-rpcgss-module.service -+After=rpc-gssd.service gssproxy.service rpc-svcgssd.service -+ - Wants=nfs-config.service - After=nfs-config.service - -diff --git a/tests/Makefile.am b/tests/Makefile.am -index faa8197..1f96264 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -11,3 +11,4 @@ SUBDIRS = nsm_client - MAINTAINERCLEANFILES = Makefile.in - - TESTS = t0001-statd-basic-mon-unmon.sh -+EXTRA_DIST = test-lib.sh $(TESTS) -diff --git a/tests/nsm_client/Makefile.am b/tests/nsm_client/Makefile.am -index 4c15346..a8fc131 100644 ---- a/tests/nsm_client/Makefile.am -+++ b/tests/nsm_client/Makefile.am -@@ -7,6 +7,7 @@ GENFILES_H = nlm_sm_inter.h - - GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) - -+EXTRA_DIST = nlm_sm_inter.x - - check_PROGRAMS = nsm_client - nsm_client_SOURCES = $(GENFILES) nsm_client.c -diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man -index 0de31b7..bee3f86 100644 ---- a/tools/mountstats/mountstats.man -+++ b/tools/mountstats/mountstats.man -@@ -1,32 +1,146 @@ - .\" - .\" mountstats(8) - .\" --.TH mountstats 8 "15 Apr 2010" -+.TH mountstats 8 "12 Dec 2014" - .SH NAME --mountstats \- Displays NFS client per-mount statistics -+mountstats \- Displays various NFS client per-mount statistics - .SH SYNOPSIS --.BI "mountstats [" "] " " [ " "]" --.SH DESCRIPTION --The - .B mountstats --command displays NFS client statisitics on each given --.I -+.RB [ \-h | \-\-help ] -+.RB [ \-v | \-\-version ] -+.RB [ \-f | \-\-file -+.IR infile ] -+.RB [ \-s | \-\-since -+.IR sincefile ] -+.\" .RB [ \-n | \-\-nfs | \-r | \-\-rpc | \-R | \-\-raw ] -+.R [ -+.RB [ \-n | \-\-nfs ] -+.R | -+.RB [ \-r | \-\-rpc ] -+.R | -+.RB [ \-R | \-\-raw ] -+.R ] -+.RI [ mountpoint ] ... -+.P -+.B mountstats iostat -+.RB [ \-h | \-\-help ] -+.RB [ \-v | \-\-version ] -+.RB [ \-f | \-\-file -+.IR infile ] -+.RB [ \-s | \-\-since -+.IR sincefile ] -+.RI [ interval ] -+.RI [ count ] -+.RI [ mountpoint ] ... -+.P -+.B mounstats nfsstat -+.RB [ \-h | \-\-help ] -+.RB [ \-v | \-\-version ] -+.RB [ \-f | \-\-file -+.IR infile ] -+.RB [ \-s | \-\-since -+.IR sincefile ] -+.RB [ \-3 ] -+.RB [ \-4 ] -+.RI [ mountpoint ] ... -+.P -+.SH DESCRIPTION -+.RB "The " mountstats " command displays various NFS client statisitics for each given" -+.IR mountpoint . -+.P -+.RI "If no " mountpoint " is given, statistics will be displayed for all NFS mountpoints on the client." -+.SS Sub-commands -+Valid -+.BR mountstats (8) -+subcommands are: -+.IP "\fBmountstats\fP" -+Display a combination of per-op RPC statistics, NFS event counts, and NFS byte counts. This is the default sub-command that will be executed if no sub-command is given. -+.IP "\fBiostat\fP" -+Display iostat-like statistics. -+.IP "\fBnfsstat\fP" -+Display nfsstat-like statistics. - .SH OPTIONS -+.SS Options valid for all sub-commands -+.TP -+.B \-h, \-\-help -+show the help message and exit -+.TP -+.B \-v, \-\-version -+show program's version number and exit -+.TP -+\fB\-f \fIinfile\fR, \fB\-\-file \fIinfile -+Read stats from -+.I infile -+instead of -+.IR /proc/self/mountstats ". " infile -+must be in the same format as -+.IR /proc/self/mountstats . -+This may be used with the -+.BR \-S | \-\-since -+options to display the delta between two different points in time. -+This may not be used with the -+.IR interval " or " count -+options of the -+.B iostat -+sub-command. - .TP --.B " \-\-nfs --display only the NFS statistics -+\fB\-S \fIsincefile\fR, \fB\-\-since \fIsincefile -+Show difference between current stats and those in -+.IR sincefile ". " sincefile -+must be in the same format as -+.IR /proc/self/mountstats . -+This may be used with the -+.BR \-f | \-\-file -+options to display the delta between two different points in time. -+This may not be used with the -+.IR interval " or " count -+options of the -+.B iostat -+sub-command. -+.SS Options specific to the mountstats sub-command -+.B \-n, \-\-nfs -+Display only the NFS statistics - .TP --.B " \-\-rpc --display only the RPC statistics -+.B \-r, \-\-rpc -+Display only the RPC statistics - .TP --.B " \-\-version --display the version of this command -+.B \-R, \-\-raw -+Display only the raw statistics. This is intended for use with the -+.BR \-f | \-\-file -+and -+.BR \-S | \-\-since -+options. -+.SS Options specific to the iostat sub-command -+.IP "\fIinterval\fP" -+Specifies the amount of time in seconds between each report. The first report contains statistics for the time since each file system was mounted. Each subsequent report contains statistics collected during the interval since the previous report. This may not be used with the -+.BR \-f | \-\-file -+or -+.BR \-s | \-\-since -+options. -+.P -+.IP "\fIcount\fP" -+Determines the number of reports generated at -+.I interval -+seconds apart. If the -+.I interval -+parameter is specified without the -+.I count -+parameter, the command generates reports continuously. This may not be used with the -+.BR \-f | \-\-file -+or -+.BR \-s | \-\-since -+options. -+.SS Options specific to the nfsstat sub-command -+.IP "\fB\-3\fP" -+Show only NFS version 3 statistics. The default is to show both version 3 and version 4 statistics. -+.IP "\fB\-4\fP" -+Show only NFS version 4 statistics. The default is to show both version 3 and version 4 statistics. - .SH FILES - .TP - .B /proc/self/mountstats - .SH SEE ALSO - .BR iostat (8), - .BR nfsiostat (8), --.BR nfsstat(8) -+.BR nfsstat (8) - .SH AUTHOR - Chuck Lever -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 1fb3e2f..fd73feb 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -24,14 +24,189 @@ MA 02110-1301 USA - """ - - import sys, os, time -+from operator import itemgetter, add -+try: -+ import argparse -+except ImportError: -+ print('%s: Failed to import argparse - make sure argparse is installed!' -+ % sys.argv[0]) -+ sys.exit(1) - --Mountstats_version = '0.2' -+Mountstats_version = '0.3' - - def difference(x, y): - """Used for a map() function - """ - return x - y - -+NfsEventCounters = [ -+ 'inoderevalidates', -+ 'dentryrevalidates', -+ 'datainvalidates', -+ 'attrinvalidates', -+ 'vfsopen', -+ 'vfslookup', -+ 'vfspermission', -+ 'vfsupdatepage', -+ 'vfsreadpage', -+ 'vfsreadpages', -+ 'vfswritepage', -+ 'vfswritepages', -+ 'vfsreaddir', -+ 'vfssetattr', -+ 'vfsflush', -+ 'vfsfsync', -+ 'vfslock', -+ 'vfsrelease', -+ 'congestionwait', -+ 'setattrtrunc', -+ 'extendwrite', -+ 'sillyrenames', -+ 'shortreads', -+ 'shortwrites', -+ 'delay', -+ 'pnfsreads', -+ 'pnfswrites' -+] -+ -+NfsByteCounters = [ -+ 'normalreadbytes', -+ 'normalwritebytes', -+ 'directreadbytes', -+ 'directwritebytes', -+ 'serverreadbytes', -+ 'serverwritebytes', -+ 'readpages', -+ 'writepages' -+] -+ -+XprtUdpCounters = [ -+ 'port', -+ 'bind_count', -+ 'rpcsends', -+ 'rpcreceives', -+ 'badxids', -+ 'inflightsends', -+ 'backlogutil' -+] -+ -+XprtTcpCounters = [ -+ 'port', -+ 'bind_count', -+ 'connect_count', -+ 'connect_time', -+ 'idle_time', -+ 'rpcsends', -+ 'rpcreceives', -+ 'badxids', -+ 'inflightsends', -+ 'backlogutil' -+] -+ -+XprtRdmaCounters = [ -+ 'port', -+ 'bind_count', -+ 'connect_count', -+ 'connect_time', -+ 'idle_time', -+ 'rpcsends', -+ 'rpcreceives', -+ 'badxids', -+ 'backlogutil', -+ 'read_chunks', -+ 'write_chunks', -+ 'reply_chunks', -+ 'total_rdma_req', -+ 'total_rdma_rep', -+ 'pullup', -+ 'fixup', -+ 'hardway', -+ 'failed_marshal', -+ 'bad_reply' -+] -+ -+Nfsv3ops = [ -+ 'NULL', -+ 'GETATTR', -+ 'SETATTR', -+ 'LOOKUP', -+ 'ACCESS', -+ 'READLINK', -+ 'READ', -+ 'WRITE', -+ 'CREATE', -+ 'MKDIR', -+ 'SYMLINK', -+ 'MKNOD', -+ 'REMOVE', -+ 'RMDIR', -+ 'RENAME', -+ 'LINK', -+ 'READDIR', -+ 'READDIRPLUS', -+ 'FSSTAT', -+ 'FSINFO', -+ 'PATHCONF', -+ 'COMMIT' -+] -+ -+Nfsv4ops = [ -+ 'NULL', -+ 'READ', -+ 'WRITE', -+ 'COMMIT', -+ 'OPEN', -+ 'OPEN_CONFIRM', -+ 'OPEN_NOATTR', -+ 'OPEN_DOWNGRADE', -+ 'CLOSE', -+ 'SETATTR', -+ 'FSINFO', -+ 'RENEW', -+ 'SETCLIENTID', -+ 'SETCLIENTID_CONFIRM', -+ 'LOCK', -+ 'LOCKT', -+ 'LOCKU', -+ 'ACCESS', -+ 'GETATTR', -+ 'LOOKUP', -+ 'LOOKUP_ROOT', -+ 'REMOVE', -+ 'RENAME', -+ 'LINK', -+ 'SYMLINK', -+ 'CREATE', -+ 'PATHCONF', -+ 'STATFS', -+ 'READLINK', -+ 'READDIR', -+ 'SERVER_CAPS', -+ 'DELEGRETURN', -+ 'GETACL', -+ 'SETACL', -+ 'FS_LOCATIONS', -+ 'RELEASE_LOCKOWNER', -+ 'SECINFO', -+ 'FSID_PRESENT', -+ 'EXCHANGE_ID', -+ 'CREATE_SESSION', -+ 'DESTROY_SESSION', -+ 'SEQUENCE', -+ 'GET_LEASE_TIME', -+ 'RECLAIM_COMPLETE', -+ 'LAYOUTGET', -+ 'GETDEVICEINFO', -+ 'LAYOUTCOMMIT', -+ 'LAYOUTRETURN', -+ 'SECINFO_NO_NAME', -+ 'TEST_STATEID', -+ 'FREE_STATEID', -+ 'GETDEVICELIST', -+ 'BIND_CONN_TO_SESSION', -+ 'DESTROY_CLIENTID' -+] -+ - class DeviceData: - """DeviceData objects provide methods for parsing and displaying - data for a single mount grabbed from /proc/self/mountstats -@@ -46,13 +221,13 @@ class DeviceData: - self.__nfs_data['export'] = words[1] - self.__nfs_data['mountpoint'] = words[4] - self.__nfs_data['fstype'] = words[7] -- if words[7].find('nfs') != -1: -+ if words[7].find('nfs') != -1 and words[7] != 'nfsd': - self.__nfs_data['statvers'] = words[8] - elif 'nfs' in words or 'nfs4' in words: - self.__nfs_data['export'] = words[0] - self.__nfs_data['mountpoint'] = words[3] - self.__nfs_data['fstype'] = words[6] -- if words[6].find('nfs') != -1: -+ if words[6].find('nfs') != -1 and words[6] != 'nfsd': - self.__nfs_data['statvers'] = words[7] - elif words[0] == 'age:': - self.__nfs_data['age'] = int(words[1]) -@@ -69,36 +244,18 @@ class DeviceData: - if self.__nfs_data['flavor'] == 6: - self.__nfs_data['pseudoflavor'] = int(keys[1].split('=')[1]) - elif words[0] == 'events:': -- self.__nfs_data['inoderevalidates'] = int(words[1]) -- self.__nfs_data['dentryrevalidates'] = int(words[2]) -- self.__nfs_data['datainvalidates'] = int(words[3]) -- self.__nfs_data['attrinvalidates'] = int(words[4]) -- self.__nfs_data['syncinodes'] = int(words[5]) -- self.__nfs_data['vfsopen'] = int(words[6]) -- self.__nfs_data['vfslookup'] = int(words[7]) -- self.__nfs_data['vfspermission'] = int(words[8]) -- self.__nfs_data['vfsreadpage'] = int(words[9]) -- self.__nfs_data['vfsreadpages'] = int(words[10]) -- self.__nfs_data['vfswritepage'] = int(words[11]) -- self.__nfs_data['vfswritepages'] = int(words[12]) -- self.__nfs_data['vfsreaddir'] = int(words[13]) -- self.__nfs_data['vfsflush'] = int(words[14]) -- self.__nfs_data['vfsfsync'] = int(words[15]) -- self.__nfs_data['vfslock'] = int(words[16]) -- self.__nfs_data['vfsrelease'] = int(words[17]) -- self.__nfs_data['setattrtrunc'] = int(words[18]) -- self.__nfs_data['extendwrite'] = int(words[19]) -- self.__nfs_data['sillyrenames'] = int(words[20]) -- self.__nfs_data['shortreads'] = int(words[21]) -- self.__nfs_data['shortwrites'] = int(words[22]) -- self.__nfs_data['delay'] = int(words[23]) -+ i = 1 -+ for key in NfsEventCounters: -+ try: -+ self.__nfs_data[key] = int(words[i]) -+ except IndexError as err: -+ self.__nfs_data[key] = 0 -+ i += 1 - elif words[0] == 'bytes:': -- self.__nfs_data['normalreadbytes'] = int(words[1]) -- self.__nfs_data['normalwritebytes'] = int(words[2]) -- self.__nfs_data['directreadbytes'] = int(words[3]) -- self.__nfs_data['directwritebytes'] = int(words[4]) -- self.__nfs_data['serverreadbytes'] = int(words[5]) -- self.__nfs_data['serverwritebytes'] = int(words[6]) -+ i = 1 -+ for key in NfsByteCounters: -+ self.__nfs_data[key] = int(words[i]) -+ i += 1 - - def __parse_rpc_line(self, words): - if words[0] == 'RPC': -@@ -107,44 +264,20 @@ class DeviceData: - elif words[0] == 'xprt:': - self.__rpc_data['protocol'] = words[1] - if words[1] == 'udp': -- self.__rpc_data['port'] = int(words[2]) -- self.__rpc_data['bind_count'] = int(words[3]) -- self.__rpc_data['rpcsends'] = int(words[4]) -- self.__rpc_data['rpcreceives'] = int(words[5]) -- self.__rpc_data['badxids'] = int(words[6]) -- self.__rpc_data['inflightsends'] = int(words[7]) -- self.__rpc_data['backlogutil'] = int(words[8]) -+ i = 2 -+ for key in XprtUdpCounters: -+ self.__rpc_data[key] = int(words[i]) -+ i += 1 - elif words[1] == 'tcp': -- self.__rpc_data['port'] = words[2] -- self.__rpc_data['bind_count'] = int(words[3]) -- self.__rpc_data['connect_count'] = int(words[4]) -- self.__rpc_data['connect_time'] = int(words[5]) -- self.__rpc_data['idle_time'] = int(words[6]) -- self.__rpc_data['rpcsends'] = int(words[7]) -- self.__rpc_data['rpcreceives'] = int(words[8]) -- self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['inflightsends'] = int(words[10]) -- self.__rpc_data['backlogutil'] = int(words[11]) -+ i = 2 -+ for key in XprtTcpCounters: -+ self.__rpc_data[key] = int(words[i]) -+ i += 1 - elif words[1] == 'rdma': -- self.__rpc_data['port'] = words[2] -- self.__rpc_data['bind_count'] = int(words[3]) -- self.__rpc_data['connect_count'] = int(words[4]) -- self.__rpc_data['connect_time'] = int(words[5]) -- self.__rpc_data['idle_time'] = int(words[6]) -- self.__rpc_data['rpcsends'] = int(words[7]) -- self.__rpc_data['rpcreceives'] = int(words[8]) -- self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['backlogutil'] = int(words[10]) -- self.__rpc_data['read_chunks'] = int(words[11]) -- self.__rpc_data['write_chunks'] = int(words[12]) -- self.__rpc_data['reply_chunks'] = int(words[13]) -- self.__rpc_data['total_rdma_req'] = int(words[14]) -- self.__rpc_data['total_rdma_rep'] = int(words[15]) -- self.__rpc_data['pullup'] = int(words[16]) -- self.__rpc_data['fixup'] = int(words[17]) -- self.__rpc_data['hardway'] = int(words[18]) -- self.__rpc_data['failed_marshal'] = int(words[19]) -- self.__rpc_data['bad_reply'] = int(words[20]) -+ i = 2 -+ for key in XprtRdmaCounters: -+ self.__rpc_data[key] = int(words[i]) -+ i += 1 - elif words[0] == 'per-op': - self.__rpc_data['per-op'] = words - else: -@@ -178,12 +311,55 @@ class DeviceData: - return True - return False - -- def display_nfs_options(self): -- """Pretty-print the NFS options -+ def nfs_version(self): -+ if self.is_nfs_mountpoint(): -+ prog, vers = self.__rpc_data['programversion'].split('/') -+ return int(vers) -+ -+ def display_raw_stats(self): -+ """Prints out stats in the same format as /proc/self/mountstats - """ -+ print('device %s mounted on %s with fstype %s %s' % \ -+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'], \ -+ self.__nfs_data['fstype'], self.__nfs_data['statvers'])) -+ print('\topts:\t%s' % ','.join(self.__nfs_data['mountoptions'])) -+ print('\tage:\t%d' % self.__nfs_data['age']) -+ print('\tcaps:\t%s' % ','.join(self.__nfs_data['servercapabilities'])) -+ print('\tsec:\tflavor=%d,pseudoflavor=%d' % (self.__nfs_data['flavor'], \ -+ self.__nfs_data['pseudoflavor'])) -+ print('\tevents:\t%s' % " ".join([str(self.__nfs_data[key]) for key in NfsEventCounters])) -+ print('\tbytes:\t%s' % " ".join([str(self.__nfs_data[key]) for key in NfsByteCounters])) -+ print('\tRPC iostats version: %1.1f p/v: %s (nfs)' % (self.__rpc_data['statsvers'], \ -+ self.__rpc_data['programversion'])) -+ if self.__rpc_data['protocol'] == 'udp': -+ print('\txprt:\tudp %s' % " ".join([str(self.__rpc_data[key]) for key in XprtUdpCounters])) -+ elif self.__rpc_data['protocol'] == 'tcp': -+ print('\txprt:\ttcp %s' % " ".join([str(self.__rpc_data[key]) for key in XprtTcpCounters])) -+ elif self.__rpc_data['protocol'] == 'rdma': -+ print('\txprt:\trdma %s' % " ".join([str(self.__rpc_data[key]) for key in XprtRdmaCounters])) -+ else: -+ raise Exception('Unknown RPC transport protocol %s' % self.__rpc_data['protocol']) -+ print('\tper-op statistics') -+ prog, vers = self.__rpc_data['programversion'].split('/') -+ if vers == '3': -+ for op in Nfsv3ops: -+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ elif vers == '4': -+ for op in Nfsv4ops: -+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ else: -+ print('\tnot implemented for version %d' % vers) -+ print() -+ -+ def display_stats_header(self): - print('Stats for %s mounted on %s:' % \ - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) - -+ def display_nfs_options(self): -+ """Pretty-print the NFS options -+ """ -+ self.display_stats_header() -+ - print(' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])) - print(' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])) - if 'nfsv4flags' in self.__nfs_data: -@@ -201,7 +377,6 @@ class DeviceData: - print('Cache events:') - print(' data cache invalidated %d times' % self.__nfs_data['datainvalidates']) - print(' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']) -- print(' inodes synced %d times' % self.__nfs_data['syncinodes']) - print() - print('VFS calls:') - print(' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']) -@@ -262,29 +437,82 @@ class DeviceData: - """ - sends = self.__rpc_data['rpcsends'] - -- # XXX: these should be sorted by 'count' -- print() -+ allstats = [] - for op in self.__rpc_data['ops']: -- stats = self.__rpc_data[op] -- count = stats[0] -- retrans = stats[1] - count -+ allstats.append([op] + self.__rpc_data[op]) -+ -+ print() -+ for stats in sorted(allstats, key=itemgetter(1), reverse=True): -+ count = stats[1] - if count != 0: -- print('%s:' % op) -+ print('%s:' % stats[0]) - print('\t%d ops (%d%%)' % \ - (count, ((count * 100) / sends)), end=' ') -- print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') -- print('\t%d major timeouts' % stats[2]) -+ retrans = stats[2] - count -+ if retrans != 0: -+ print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') -+ print('\t%d major timeouts' % stats[3]) -+ else: -+ print('') - print('\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ -- (stats[3] / count, stats[4] / count)) -- print('\tbacklog wait: %f' % (float(stats[5]) / count), end=' ') -- print('\tRTT: %f' % (float(stats[6]) / count), end=' ') -+ (stats[4] / count, stats[5] / count)) -+ print('\tbacklog wait: %f' % (float(stats[6]) / count), end=' ') -+ print('\tRTT: %f' % (float(stats[7]) / count), end=' ') - print('\ttotal execute time: %f (milliseconds)' % \ -- (float(stats[7]) / count)) -+ (float(stats[8]) / count)) -+ -+ def client_rpc_stats(self): -+ """Tally high-level rpc stats for the nfsstat command -+ """ -+ sends = 0 -+ trans = 0 -+ authrefrsh = 0 -+ for op in self.__rpc_data['ops']: -+ sends += self.__rpc_data[op][0] -+ trans += self.__rpc_data[op][1] -+ retrans = trans - sends -+ # authrefresh stats don't actually get captured in -+ # /proc/self/mountstats, so we fudge it here -+ authrefrsh = sends -+ return (sends, trans, authrefrsh) -+ -+ def display_nfsstat_stats(self): -+ """Pretty-print nfsstat-style stats -+ """ -+ sends = 0 -+ for op in self.__rpc_data['ops']: -+ sends += self.__rpc_data[op][0] -+ if sends == 0: -+ return -+ print() -+ vers = self.nfs_version() -+ print('Client nfs v%d' % vers) -+ info = [] -+ for op in self.__rpc_data['ops']: -+ print('%-13s' % str.lower(op)[:12], end='') -+ count = self.__rpc_data[op][0] -+ pct = (count * 100) / sends -+ info.append((count, pct)) -+ if (self.__rpc_data['ops'].index(op) + 1) % 6 == 0: -+ print() -+ for (count, pct) in info: -+ print('%-8u%3u%% ' % (count, pct), end='') -+ print() -+ info = [] -+ print() -+ if len(info) > 0: -+ for (count, pct) in info: -+ print('%-8u%3u%% ' % (count, pct), end='') -+ print() - - def compare_iostats(self, old_stats): - """Return the difference between two sets of stats - """ -+ if old_stats.__nfs_data['age'] > self.__nfs_data['age']: -+ return self -+ - result = DeviceData() -+ protocol = self.__rpc_data['protocol'] - - # copy self into result - for key, value in self.__nfs_data.items(): -@@ -299,70 +527,118 @@ class DeviceData: - for op in result.__rpc_data['ops']: - result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) - -- # update the remaining keys we care about -- result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -- result.__rpc_data['backlogutil'] -= old_stats.__rpc_data['backlogutil'] -- result.__nfs_data['serverreadbytes'] -= old_stats.__nfs_data['serverreadbytes'] -- result.__nfs_data['serverwritebytes'] -= old_stats.__nfs_data['serverwritebytes'] -- -+ # update the remaining keys -+ if protocol == 'udp': -+ for key in XprtUdpCounters: -+ result.__rpc_data[key] -= old_stats.__rpc_data[key] -+ elif protocol == 'tcp': -+ for key in XprtTcpCounters: -+ result.__rpc_data[key] -= old_stats.__rpc_data[key] -+ elif protocol == 'rdma': -+ for key in XprtRdmaCounters: -+ result.__rpc_data[key] -= old_stats.__rpc_data[key] -+ result.__nfs_data['age'] -= old_stats.__nfs_data['age'] -+ for key in NfsEventCounters: -+ result.__nfs_data[key] -= old_stats.__nfs_data[key] -+ for key in NfsByteCounters: -+ result.__nfs_data[key] -= old_stats.__nfs_data[key] - return result - -+ def setup_accumulator(self, ops): -+ """Initialize a DeviceData instance to tally stats for all mountpoints -+ with the same major version. This is for the nfsstat command. -+ """ -+ if ops == Nfsv3ops: -+ self.__rpc_data['programversion'] = '100003/3' -+ self.__nfs_data['fstype'] = 'nfs' -+ elif ops == Nfsv4ops: -+ self.__rpc_data['programversion'] = '100003/4' -+ self.__nfs_data['fstype'] = 'nfs4' -+ self.__rpc_data['ops'] = ops -+ for op in ops: -+ self.__rpc_data[op] = [0 for i in range(8)] -+ -+ def accumulate_iostats(self, new_stats): -+ """Accumulate counters from all RPC op buckets in new_stats. This is -+ 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])) -+ -+ def __print_rpc_op_stats(self, op, sample_time): -+ """Print generic stats for one RPC op -+ """ -+ if op not in self.__rpc_data: -+ return -+ -+ rpc_stats = self.__rpc_data[op] -+ ops = float(rpc_stats[0]) -+ retrans = float(rpc_stats[1] - rpc_stats[0]) -+ kilobytes = float(rpc_stats[3] + rpc_stats[4]) / 1024 -+ rtt = float(rpc_stats[6]) -+ exe = float(rpc_stats[7]) -+ -+ # prevent floating point exceptions -+ if ops != 0: -+ kb_per_op = kilobytes / ops -+ retrans_percent = (retrans * 100) / ops -+ rtt_per_op = rtt / ops -+ exe_per_op = exe / ops -+ else: -+ kb_per_op = 0.0 -+ retrans_percent = 0.0 -+ rtt_per_op = 0.0 -+ exe_per_op = 0.0 -+ -+ op += ':' -+ print(format(op.lower(), '<16s'), end='') -+ print(format('ops/s', '>8s'), end='') -+ print(format('kB/s', '>16s'), end='') -+ print(format('kB/op', '>16s'), end='') -+ print(format('retrans', '>16s'), end='') -+ print(format('avg RTT (ms)', '>16s'), end='') -+ print(format('avg exe (ms)', '>16s')) -+ -+ print(format((ops / sample_time), '>24.3f'), end='') -+ print(format((kilobytes / sample_time), '>16.3f'), end='') -+ print(format(kb_per_op, '>16.3f'), end='') -+ retransmits = '{0:>10.0f} ({1:>3.1f}%)'.format(retrans, retrans_percent).strip() -+ print(format(retransmits, '>16'), end='') -+ print(format(rtt_per_op, '>16.3f'), end='') -+ print(format(exe_per_op, '>16.3f')) -+ - def display_iostats(self, sample_time): - """Display NFS and RPC stats in an iostat-like way - """ - sends = float(self.__rpc_data['rpcsends']) - if sample_time == 0: - sample_time = float(self.__nfs_data['age']) -+ # sample_time could still be zero if the export was just mounted. -+ # Set it to 1 to avoid divide by zero errors in this case since we'll -+ # likely still have relevant mount statistics to show. -+ # -+ if sample_time == 0: -+ sample_time = 1; -+ if sends != 0: -+ backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time -+ else: -+ backlog = 0.0 - - print() - print('%s mounted on %s:' % \ - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) -+ print() - -- print('\top/s\trpc bklog') -- print('\t%.2f' % (sends / sample_time), end=' ') -- if sends != 0: -- print('\t%.2f' % \ -- ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)) -- else: -- print('\t0.00') -- -- # reads: ops/s, kB/s, avg rtt, and avg exe -- # XXX: include avg xfer size and retransmits? -- read_rpc_stats = self.__rpc_data['READ'] -- ops = float(read_rpc_stats[0]) -- kilobytes = float(self.__nfs_data['serverreadbytes']) / 1024 -- rtt = float(read_rpc_stats[6]) -- exe = float(read_rpc_stats[7]) -- -- print('\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -- print('\t\t%.2f' % (ops / sample_time), end=' ') -- print('\t\t%.2f' % (kilobytes / sample_time), end=' ') -- if ops != 0: -- print('\t\t%.2f' % (rtt / ops), end=' ') -- print('\t\t%.2f' % (exe / ops)) -- else: -- print('\t\t0.00', end=' ') -- print('\t\t0.00') -- -- # writes: ops/s, kB/s, avg rtt, and avg exe -- # XXX: include avg xfer size and retransmits? -- write_rpc_stats = self.__rpc_data['WRITE'] -- ops = float(write_rpc_stats[0]) -- kilobytes = float(self.__nfs_data['serverwritebytes']) / 1024 -- rtt = float(write_rpc_stats[6]) -- exe = float(write_rpc_stats[7]) -- -- print('\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -- print('\t\t%.2f' % (ops / sample_time), end=' ') -- print('\t\t%.2f' % (kilobytes / sample_time), end=' ') -- if ops != 0: -- print('\t\t%.2f' % (rtt / ops), end=' ') -- print('\t\t%.2f' % (exe / ops)) -- else: -- print('\t\t0.00', end=' ') -- print('\t\t0.00') -+ print(format('ops/s', '>16') + format('rpc bklog', '>16')) -+ print(format((sends / sample_time), '>16.3f'), end='') -+ print(format(backlog, '>16.3f')) -+ print() - --def parse_stats_file(filename): -+ self.__print_rpc_op_stats('READ', sample_time) -+ self.__print_rpc_op_stats('WRITE', sample_time) -+ sys.stdout.flush() -+ -+def parse_stats_file(f): - """pop the contents of a mountstats file into a dictionary, - keyed by mount point. each value object is a list of the - lines in the mountstats file corresponding to the mount -@@ -371,7 +647,7 @@ def parse_stats_file(filename): - ms_dict = dict() - key = '' - -- f = open(filename) -+ f.seek(0) - for line in f.readlines(): - words = line.split() - if len(words) == 0: -@@ -385,132 +661,154 @@ def parse_stats_file(filename): - else: - new += [ line.strip() ] - ms_dict[key] = new -- f.close - - return ms_dict - --def print_mountstats_help(name): -- print('usage: %s [ options ] ' % name) -- print() -- print(' Version %s' % Mountstats_version) -- print() -- print(' Display NFS client per-mount statistics.') -- print() -- print(' --version display the version of this command') -- print(' --nfs display only the NFS statistics') -- print(' --rpc display only the RPC statistics') -- print(' --start sample and save statistics') -- print(' --end resample statistics and compare them with saved') -+def print_mountstats(stats, nfs_only, rpc_only, raw): -+ if nfs_only: -+ stats.display_nfs_options() -+ stats.display_nfs_events() -+ stats.display_nfs_bytes() -+ elif rpc_only: -+ stats.display_stats_header() -+ stats.display_rpc_generic_stats() -+ stats.display_rpc_op_stats() -+ elif raw: -+ stats.display_raw_stats() -+ else: -+ stats.display_nfs_options() -+ stats.display_nfs_bytes() -+ stats.display_rpc_generic_stats() -+ stats.display_rpc_op_stats() - print() - --def mountstats_command(): -+def mountstats_command(args): - """Mountstats command - """ -- mountpoints = [] -- nfs_only = False -- rpc_only = False -- -- for arg in sys.argv: -- if arg in ['-h', '--help', 'help', 'usage']: -- print_mountstats_help(prog) -- return -- -- if arg in ['-v', '--version', 'version']: -- print('%s version %s' % (sys.argv[0], Mountstats_version)) -- sys.exit(0) -- -- if arg in ['-n', '--nfs']: -- nfs_only = True -- continue -- -- if arg in ['-r', '--rpc']: -- rpc_only = True -- continue -+ mountstats = parse_stats_file(args.infile) -+ mountpoints = args.mountpoints - -- if arg in ['-s', '--start']: -- raise Exception('Sampling is not yet implemented') -+ # make certain devices contains only NFS mount points -+ if len(mountpoints) > 0: -+ check = [] -+ for device in mountpoints: -+ stats = DeviceData() -+ try: -+ stats.parse_stats(mountstats[device]) -+ if stats.is_nfs_mountpoint(): -+ check += [device] -+ except KeyError: -+ continue -+ mountpoints = check -+ else: -+ for device, descr in mountstats.items(): -+ stats = DeviceData() -+ stats.parse_stats(descr) -+ if stats.is_nfs_mountpoint(): -+ mountpoints += [device] -+ if len(mountpoints) == 0: -+ print('No NFS mount points were found') -+ return - -- if arg in ['-e', '--end']: -- raise Exception('Sampling is not yet implemented') -+ if args.since: -+ old_mountstats = parse_stats_file(args.since) - -- if arg == sys.argv[0]: -- continue -+ for mp in mountpoints: -+ stats = DeviceData() -+ stats.parse_stats(mountstats[mp]) -+ if not args.since: -+ print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw) -+ elif args.since and mp not in old_mountstats: -+ print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw) -+ else: -+ old_stats = DeviceData() -+ old_stats.parse_stats(old_mountstats[mp]) -+ diff_stats = stats.compare_iostats(old_stats) -+ print_mountstats(diff_stats, args.nfs_only, args.rpc_only, args.raw) - -- mountpoints += [arg] -+ args.infile.close() -+ if args.since: -+ args.since.close() - -- if mountpoints == []: -- print_mountstats_help(prog) -- return -+def nfsstat_command(args): -+ """nfsstat-like command for NFS mount points -+ """ -+ mountstats = parse_stats_file(args.infile) -+ mountpoints = args.mountpoints -+ v3stats = DeviceData() -+ v3stats.setup_accumulator(Nfsv3ops) -+ v4stats = DeviceData() -+ v4stats.setup_accumulator(Nfsv4ops) -+ -+ # ensure stats get printed if neither v3 nor v4 was specified -+ if args.show_v3 or args.show_v4: -+ show_both = False -+ else: -+ show_both = True - -- if rpc_only == True and nfs_only == True: -- print_mountstats_help(prog) -+ # make certain devices contains only NFS mount points -+ if len(mountpoints) > 0: -+ check = [] -+ for device in mountpoints: -+ stats = DeviceData() -+ try: -+ stats.parse_stats(mountstats[device]) -+ if stats.is_nfs_mountpoint(): -+ check += [device] -+ except KeyError: -+ continue -+ mountpoints = check -+ else: -+ for device, descr in mountstats.items(): -+ stats = DeviceData() -+ stats.parse_stats(descr) -+ if stats.is_nfs_mountpoint(): -+ mountpoints += [device] -+ if len(mountpoints) == 0: -+ print('No NFS mount points were found') - return - -- mountstats = parse_stats_file('/proc/self/mountstats') -+ if args.since: -+ old_mountstats = parse_stats_file(args.since) - - for mp in mountpoints: -- if mp not in mountstats: -- print('Statistics for mount point %s not found' % mp) -- continue -- - stats = DeviceData() - stats.parse_stats(mountstats[mp]) -+ vers = stats.nfs_version() - -- if not stats.is_nfs_mountpoint(): -- print('Mount point %s exists but is not an NFS mount' % mp) -- continue -- -- if nfs_only: -- stats.display_nfs_options() -- stats.display_nfs_events() -- stats.display_nfs_bytes() -- elif rpc_only: -- stats.display_rpc_generic_stats() -- stats.display_rpc_op_stats() -+ if not args.since: -+ acc_stats = stats -+ elif args.since and mp not in old_mountstats: -+ acc_stats = stats - else: -- stats.display_nfs_options() -- stats.display_nfs_bytes() -- stats.display_rpc_generic_stats() -- stats.display_rpc_op_stats() -+ old_stats = DeviceData() -+ old_stats.parse_stats(old_mountstats[mp]) -+ acc_stats = stats.compare_iostats(old_stats) - --def print_nfsstat_help(name): -- print('usage: %s [ options ]' % name) -- print() -- print(' Version %s' % Mountstats_version) -- print() -- print(' nfsstat-like program that uses NFS client per-mount statistics.') -- print() -+ if vers == 3 and (show_both or args.show_v3): -+ v3stats.accumulate_iostats(acc_stats) -+ elif vers == 4 and (show_both or args.show_v4): -+ v4stats.accumulate_iostats(acc_stats) - --def nfsstat_command(): -- print_nfsstat_help(prog) -+ sends, retrans, authrefrsh = map(add, v3stats.client_rpc_stats(), v4stats.client_rpc_stats()) -+ print('Client rpc stats:') -+ print('calls retrans authrefrsh') -+ print('%-11u%-11u%-11u' % (sends, retrans, authrefrsh)) - --def print_iostat_help(name): -- print('usage: %s [ [ ] ] [ ] ' % name) -- print() -- print(' Version %s' % Mountstats_version) -- print() -- print(' iostat-like program to display NFS client per-mount statistics.') -- print() -- print(' The parameter specifies the amount of time in seconds between') -- print(' each report. The first report contains statistics for the time since each') -- print(' file system was mounted. Each subsequent report contains statistics') -- print(' collected during the interval since the previous report.') -- print() -- print(' If the parameter is specified, the value of determines the') -- print(' number of reports generated at seconds apart. If the interval') -- print(' parameter is specified without the parameter, the command generates') -- print(' reports continuously.') -- print() -- print(' If one or more names are specified, statistics for only these') -- print(' mount points will be displayed. Otherwise, all NFS mount points on the') -- print(' client are listed.') -- print() -+ if show_both or args.show_v3: -+ v3stats.display_nfsstat_stats() -+ if show_both or args.show_v4: -+ v4stats.display_nfsstat_stats() -+ -+ args.infile.close() -+ if args.since: -+ args.since.close() - - def print_iostat_summary(old, new, devices, time): - for device in devices: - stats = DeviceData() - stats.parse_stats(new[device]) -- if not old: -+ if not old or device not in old: - stats.display_iostats(time) - else: - old_stats = DeviceData() -@@ -518,51 +816,28 @@ def print_iostat_summary(old, new, devices, time): - diff_stats = stats.compare_iostats(old_stats) - diff_stats.display_iostats(time) - --def iostat_command(): -+def iostat_command(args): - """iostat-like command for NFS mount points - """ -- mountstats = parse_stats_file('/proc/self/mountstats') -- devices = [] -- interval_seen = False -- count_seen = False -- -- for arg in sys.argv: -- if arg in ['-h', '--help', 'help', 'usage']: -- print_iostat_help(prog) -- return -- -- if arg in ['-v', '--version', 'version']: -- print('%s version %s' % (sys.argv[0], Mountstats_version)) -- return -- -- if arg == sys.argv[0]: -- continue -+ mountstats = parse_stats_file(args.infile) -+ devices = args.mountpoints - -- if arg in mountstats: -- devices += [arg] -- elif not interval_seen: -- interval = int(arg) -- if interval > 0: -- interval_seen = True -- else: -- print('Illegal value') -- return -- elif not count_seen: -- count = int(arg) -- if count > 0: -- count_seen = True -- else: -- print('Illegal value') -- return -+ if args.since: -+ old_mountstats = parse_stats_file(args.since) -+ else: -+ old_mountstats = None - - # make certain devices contains only NFS mount points - if len(devices) > 0: - check = [] - for device in devices: - stats = DeviceData() -- stats.parse_stats(mountstats[device]) -- if stats.is_nfs_mountpoint(): -- check += [device] -+ try: -+ stats.parse_stats(mountstats[device]) -+ if stats.is_nfs_mountpoint(): -+ check += [device] -+ except KeyError: -+ continue - devices = check - else: - for device, descr in mountstats.items(): -@@ -574,43 +849,145 @@ def iostat_command(): - print('No NFS mount points were found') - return - -- old_mountstats = None - sample_time = 0 - -- if not interval_seen: -+ if args.interval is None: - print_iostat_summary(old_mountstats, mountstats, devices, sample_time) - return - -- if count_seen: -+ if args.count is not None: -+ count = args.count - while count != 0: - print_iostat_summary(old_mountstats, mountstats, devices, sample_time) - old_mountstats = mountstats -- time.sleep(interval) -- sample_time = interval -- mountstats = parse_stats_file('/proc/self/mountstats') -+ time.sleep(args.interval) -+ sample_time = args.interval -+ mountstats = parse_stats_file(args.infile) - count -= 1 - else: - while True: - print_iostat_summary(old_mountstats, mountstats, devices, sample_time) - old_mountstats = mountstats -- time.sleep(interval) -- sample_time = interval -- mountstats = parse_stats_file('/proc/self/mountstats') -+ time.sleep(args.interval) -+ sample_time = args.interval -+ mountstats = parse_stats_file(args.infile) - --# --# Main --# --prog = os.path.basename(sys.argv[0]) -+ args.infile.close() -+ if args.since: -+ args.since.close() -+ -+class ICMAction(argparse.Action): -+ """Custom action to deal with interval, count, and mountpoints. -+ """ -+ def __call__(self, parser, namespace, values, option_string=None): -+ if namespace.mountpoints is None: -+ namespace.mountpoints = [] -+ if values is None: -+ return -+ elif (type(values) == type([])): -+ for value in values: -+ self._handle_one(namespace, value) -+ else: -+ self._handle_one(namespace, values) -+ -+ def _handle_one(self, namespace, value): -+ try: -+ intval = int(value) -+ if namespace.infile.name != '/proc/self/mountstats': -+ raise argparse.ArgumentError(self, "not allowed with argument -f/--file or -S/--since") -+ self._handle_int(namespace, intval) -+ except ValueError: -+ namespace.mountpoints.append(value) -+ -+ def _handle_int(self, namespace, value): -+ if namespace.interval is None: -+ namespace.interval = value -+ elif namespace.count is None: -+ namespace.count = value -+ else: -+ raise argparse.ArgumentError(self, "too many integer arguments") -+ -+def main(): -+ parser = argparse.ArgumentParser(epilog='For specific sub-command help, ' -+ 'run \'mountstats SUB-COMMAND -h|--help\'') -+ subparsers = parser.add_subparsers(help='sub-command help') -+ -+ common_parser = argparse.ArgumentParser(add_help=False) -+ common_parser.add_argument('-v', '--version', action='version', -+ version='mountstats ' + Mountstats_version) -+ common_parser.add_argument('-f', '--file', default=open('/proc/self/mountstats', 'r'), -+ type=argparse.FileType('r'), dest='infile', -+ help='Read stats from %(dest)s instead of /proc/self/mountstats') -+ common_parser.add_argument('-S', '--since', type=argparse.FileType('r'), -+ metavar='SINCEFILE', -+ help='Show difference between current stats and those in SINCEFILE') -+ -+ mountstats_parser = subparsers.add_parser('mountstats', -+ parents=[common_parser], -+ help='Display a combination of per-op RPC statistics, NFS event counts, and NFS byte counts. ' -+ 'This is the default sub-command if no sub-command is given.') -+ group = mountstats_parser.add_mutually_exclusive_group() -+ group.add_argument('-n', '--nfs', action='store_true', dest='nfs_only', -+ help='Display only the NFS statistics') -+ group.add_argument('-r', '--rpc', action='store_true', dest='rpc_only', -+ help='Display only the RPC statistics') -+ group.add_argument('-R', '--raw', action='store_true', -+ help='Display only the raw statistics') -+ # The mountpoints argument cannot be moved into the common_parser because -+ # it will screw up the parsing of the iostat arguments (interval and count) -+ mountstats_parser.add_argument('mountpoints', nargs='*', metavar='mountpoint', -+ help='Display statistics for this mountpoint. More than one may be specified. ' -+ 'If absent, statistics for all NFS mountpoints will be generated.') -+ mountstats_parser.set_defaults(func=mountstats_command) -+ -+ nfsstat_parser = subparsers.add_parser('nfsstat', -+ parents=[common_parser], -+ help='Display nfsstat-like statistics.') -+ nfsstat_parser.add_argument('-3', action='store_true', dest='show_v3', -+ help='Show NFS version 3 statistics') -+ nfsstat_parser.add_argument('-4', action='store_true', dest='show_v4', -+ help='Show NFS version 4 statistics') -+ # The mountpoints argument cannot be moved into the common_parser because -+ # it will screw up the parsing of the iostat arguments (interval and count) -+ nfsstat_parser.add_argument('mountpoints', nargs='*', metavar='mountpoint', -+ help='Display statistics for this mountpoint. More than one may be specified. ' -+ 'If absent, statistics for all NFS mountpoints will be generated.') -+ nfsstat_parser.set_defaults(func=nfsstat_command) -+ -+ iostat_parser = subparsers.add_parser('iostat', -+ parents=[common_parser], -+ help='Display iostat-like statistics.') -+ iostat_parser.add_argument('interval', nargs='?', action=ICMAction, -+ help='Number of seconds between reports. If absent, only one report will ' -+ 'be generated.') -+ iostat_parser.add_argument('count', nargs='?', action=ICMAction, -+ help='Number of reports generated at seconds apart. If absent, ' -+ 'reports will be generated continuously.') -+ # The mountpoints argument cannot be moved into the common_parser because -+ # it will screw up the parsing of the iostat arguments (interval and count) -+ iostat_parser.add_argument('mountpoints', nargs='*', action=ICMAction, metavar='mountpoint', -+ help='Display statsistics for this mountpoint. More than one may be specified. ' -+ 'If absent, statistics for all NFS mountpoints will be generated.') -+ iostat_parser.set_defaults(func=iostat_command) -+ -+ args = parser.parse_args() -+ return args.func(args) - - try: -- if prog == 'mountstats': -- mountstats_command() -- elif prog == 'ms-nfsstat': -- nfsstat_command() -- elif prog == 'ms-iostat': -- iostat_command() --except KeyboardInterrupt: -- print('Caught ^C... exiting') -+ if __name__ == '__main__': -+ # Run the mounstats sub-command if no sub-command (or the help flag) -+ # is given. If the argparse module ever gets support for optional -+ # (default) sub-commands, then this can be changed. -+ if len(sys.argv) == 1: -+ sys.argv.insert(1, 'mountstats') -+ elif sys.argv[1] not in ['-h', '--help', 'mountstats', 'iostat', 'nfsstat']: -+ sys.argv.insert(1, 'mountstats') -+ res = main() -+ sys.stdout.close() -+ sys.stderr.close() -+ sys.exit(res) -+except (SystemExit, KeyboardInterrupt, RuntimeError): - sys.exit(1) -+except IOError: -+ pass - --sys.exit(0) -diff --git a/tools/rpcgen/rpc_main.c b/tools/rpcgen/rpc_main.c -index 28aa60c..f81da47 100644 ---- a/tools/rpcgen/rpc_main.c -+++ b/tools/rpcgen/rpc_main.c -@@ -44,6 +44,7 @@ static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI"; - #include - #include - #include -+#include - #include "rpc_parse.h" - #include "rpc_util.h" - #include "rpc_scan.h" -@@ -389,7 +390,7 @@ c_output(char *infile, char *define, int extend, char *outfile) - open_output(infile, outfilename); - add_warning(); - if (infile && (include = extendfile(infile, ".h"))) { -- f_print(fout, "#include \"%s\"\n", include); -+ f_print(fout, "#include \"%s\"\n", basename(include)); - free(include); - /* .h file already contains rpc/rpc.h */ - } else -@@ -523,7 +524,7 @@ s_output(int argc, char **argv, char *infile, char *define, int extend, - open_output(infile, outfilename); - add_warning(); - if (infile && (include = extendfile(infile, ".h"))) { -- f_print(fout, "#include \"%s\"\n", include); -+ f_print(fout, "#include \"%s\"\n", basename(include)); - free(include); - } else - f_print(fout, "#include \n"); -@@ -630,7 +631,7 @@ l_output(char *infile, char *define, int extend, char *outfile) - if (Cflag) - f_print (fout, "#include /* for memset */\n"); - if (infile && (include = extendfile(infile, ".h"))) { -- f_print(fout, "#include \"%s\"\n", include); -+ f_print(fout, "#include \"%s\"\n", basename(include)); - free(include); - } else - f_print(fout, "#include \n"); -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index bdea12b..48eac00 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -47,7 +47,7 @@ static void error(nfs_export *exp, int err); - static void usage(const char *progname, int n); - static void validate_export(nfs_export *exp); - static int matchhostname(const char *hostname1, const char *hostname2); --static void export_d_read(const char *dname); -+static int export_d_read(const char *dname); - static void grab_lockfile(void); - static void release_lockfile(void); - -@@ -182,8 +182,11 @@ main(int argc, char **argv) - atexit(release_lockfile); - - if (f_export && ! f_ignore) { -- export_read(_PATH_EXPORTS); -- export_d_read(_PATH_EXPORTS_D); -+ if (! (export_read(_PATH_EXPORTS) + -+ export_d_read(_PATH_EXPORTS_D))) { -+ if (f_verbose) -+ xlog(L_WARNING, "No file systems exported!"); -+ } - } - if (f_export) { - if (f_all) -@@ -685,21 +688,22 @@ out: - - /* Based on mnt_table_parse_dir() in - util-linux-ng/shlibs/mount/src/tab_parse.c */ --static void -+static int - export_d_read(const char *dname) - { - int n = 0, i; - struct dirent **namelist = NULL; -+ int volumes = 0; - - - n = scandir(dname, &namelist, NULL, versionsort); - if (n < 0) { - if (errno == ENOENT) - /* Silently return */ -- return; -+ return volumes; - xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); - } else if (n == 0) -- return; -+ return volumes; - - for (i = 0; i < n; i++) { - struct dirent *d = namelist[i]; -@@ -729,14 +733,14 @@ export_d_read(const char *dname) - continue; - } - -- export_read(fname); -+ volumes += export_read(fname); - } - - for (i = 0; i < n; i++) - free(namelist[i]); - free(namelist); - -- return; -+ return volumes; - } - - static char -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index 9835117..62a70af 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -15,7 +15,6 @@ endif - sbin_PROGRAMS = $(sbin_PREFIXED) - - EXTRA_DIST = \ -- gss_destroy_creds \ - $(man8_MANS) - - COMMON_SRCS = \ -@@ -46,8 +45,8 @@ gssd_SOURCES = \ - write_bytes.h - - gssd_LDADD = ../../support/nfs/libnfs.a \ -- $(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS) --gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC) -+ $(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC) -+gssd_LDFLAGS = $(KRBLDFLAGS) - - gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS) -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 121feb1..1d8e6a7 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -78,6 +78,7 @@ - #include "nfsrpc.h" - #include "nfslib.h" - #include "gss_names.h" -+#include "misc.h" - - /* - * pollarray: -@@ -1250,7 +1251,7 @@ void - handle_gssd_upcall(struct clnt_info *clp) - { - uid_t uid; -- char *lbuf = NULL; -+ char lbuf[RPC_CHAN_BUF_SIZE]; - int lbuflen = 0; - char *p; - char *mech = NULL; -@@ -1260,11 +1261,14 @@ handle_gssd_upcall(struct clnt_info *clp) - - printerr(1, "handling gssd upcall (%s)\n", clp->dirname); - -- if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) { -+ lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf)); -+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed reading request\n"); - return; - } -+ lbuf[lbuflen-1] = 0; -+ - printerr(2, "%s: '%s'\n", __func__, lbuf); - - /* find the mechanism name */ -@@ -1362,7 +1366,6 @@ handle_gssd_upcall(struct clnt_info *clp) - } - - out: -- free(lbuf); - free(mech); - free(enctypes); - free(target); -diff --git a/utils/gssd/svcgssd.h b/utils/gssd/svcgssd.h -index 9a2e2e8..02b5c7a 100644 ---- a/utils/gssd/svcgssd.h -+++ b/utils/gssd/svcgssd.h -@@ -35,7 +35,7 @@ - #include - #include - --void handle_nullreq(FILE *f); -+void handle_nullreq(int f); - void gssd_run(void); - - #define GSSD_SERVICE_NAME "nfs" -diff --git a/utils/gssd/svcgssd_main_loop.c b/utils/gssd/svcgssd_main_loop.c -index 2b4111c..b5681ce 100644 ---- a/utils/gssd/svcgssd_main_loop.c -+++ b/utils/gssd/svcgssd_main_loop.c -@@ -54,19 +54,18 @@ void - gssd_run() - { - int ret; -- FILE *f; -+ int f; - struct pollfd pollfd; - - #define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" - -- f = fopen(NULLRPC_FILE, "rw"); -- -- if (!f) { -+ f = open(NULLRPC_FILE, O_RDWR); -+ if (f < 0) { - printerr(0, "failed to open %s: %s\n", - NULLRPC_FILE, strerror(errno)); - exit(1); - } -- pollfd.fd = fileno(f); -+ pollfd.fd = f; - pollfd.events = POLLIN; - while (1) { - int save_err; -diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c -index 5bdb438..72ec254 100644 ---- a/utils/gssd/svcgssd_proc.c -+++ b/utils/gssd/svcgssd_proc.c -@@ -73,36 +73,35 @@ struct svc_cred { - int cr_ngroups; - gid_t cr_groups[NGROUPS]; - }; --static char vbuf[RPC_CHAN_BUF_SIZE]; - - static int - do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, - gss_OID mech, gss_buffer_desc *context_token, - int32_t endtime, char *client_name) - { -- FILE *f; -- int i; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int i, f, err, blen; - char *fname = NULL; -- int err; - - printerr(1, "doing downcall\n"); - if ((fname = mech2file(mech)) == NULL) - goto out_err; -- f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w"); -- if (f == NULL) { -+ -+ f = open(SVCGSSD_CONTEXT_CHANNEL, O_WRONLY); -+ if (f < 0) { - printerr(0, "WARNING: unable to open downcall channel " - "%s: %s\n", - SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); - goto out_err; - } -- setvbuf(f, vbuf, _IOLBF, RPC_CHAN_BUF_SIZE); -- qword_printhex(f, out_handle->value, out_handle->length); -+ bp = buf, blen = sizeof(buf); -+ qword_addhex(&bp, &blen, out_handle->value, out_handle->length); - /* XXX are types OK for the rest of this? */ - /* For context cache, use the actual context endtime */ -- qword_printint(f, endtime); -- qword_printint(f, cred->cr_uid); -- qword_printint(f, cred->cr_gid); -- qword_printint(f, cred->cr_ngroups); -+ qword_addint(&bp, &blen, endtime); -+ qword_addint(&bp, &blen, cred->cr_uid); -+ qword_addint(&bp, &blen, cred->cr_gid); -+ qword_addint(&bp, &blen, cred->cr_ngroups); - printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), " - "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n", - fname, out_handle->length, context_token->length, -@@ -110,19 +109,21 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, - client_name ? client_name : "", - cred->cr_uid, cred->cr_gid, cred->cr_ngroups); - for (i=0; i < cred->cr_ngroups; i++) { -- qword_printint(f, cred->cr_groups[i]); -+ qword_addint(&bp, &blen, cred->cr_groups[i]); - printerr(2, " (%4d) %d\n", i+1, cred->cr_groups[i]); - } -- qword_print(f, fname); -- qword_printhex(f, context_token->value, context_token->length); -+ qword_add(&bp, &blen, fname); -+ qword_addhex(&bp, &blen, context_token->value, context_token->length); - if (client_name) -- qword_print(f, client_name); -- err = qword_eol(f); -- if (err) { -+ qword_add(&bp, &blen, client_name); -+ qword_addeol(&bp, &blen); -+ err = 0; -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) { - printerr(1, "WARNING: error writing to downcall channel " - "%s: %s\n", SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); -+ err = -1; - } -- fclose(f); -+ close(f); - return err; - out_err: - printerr(1, "WARNING: downcall failed\n"); -@@ -317,7 +318,7 @@ print_hexl(const char *description, unsigned char *cp, int length) - #endif - - void --handle_nullreq(FILE *f) { -+handle_nullreq(int f) { - /* XXX initialize to a random integer to reduce chances of unnecessary - * invalidation of existing ctx's on restarting svcgssd. */ - static u_int32_t handle_seq = 0; -@@ -339,19 +340,21 @@ handle_nullreq(FILE *f) { - u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; - u_int32_t ignore_min_stat; - struct svc_cred cred; -- static char *lbuf = NULL; -- static int lbuflen = 0; -- static char *cp; -+ char lbuf[RPC_CHAN_BUF_SIZE]; -+ int lbuflen = 0; -+ char *cp; - int32_t ctx_endtime; - char *hostbased_name = NULL; - - printerr(1, "handling null request\n"); - -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) { -+ lbuflen = read(f, lbuf, sizeof(lbuf)); -+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { - printerr(0, "WARNING: handle_nullreq: " - "failed reading request\n"); - return; - } -+ lbuf[lbuflen-1] = 0; - - cp = lbuf; - -diff --git a/utils/gssd/write_bytes.h b/utils/gssd/write_bytes.h -index 4fc72cc..b3f342b 100644 ---- a/utils/gssd/write_bytes.h -+++ b/utils/gssd/write_bytes.h -@@ -32,6 +32,7 @@ - #define _WRITE_BYTES_H_ - - #include -+#include - #include - #include /* for ntohl */ - -diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am -index 58b33ec..c2f8ba1 100644 ---- a/utils/idmapd/Makefile.am -+++ b/utils/idmapd/Makefile.am -@@ -7,8 +7,7 @@ KPREFIX = @kprefix@ - sbin_PROGRAMS = idmapd - - EXTRA_DIST = \ -- $(man8_MANS) \ -- idmapd.conf -+ $(man8_MANS) - - idmapd_SOURCES = \ - idmapd.c \ -diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am -index 5810936..e24f3bd 100644 ---- a/utils/mount/Makefile.am -+++ b/utils/mount/Makefile.am -@@ -8,19 +8,21 @@ man8_MANS = mount.nfs.man umount.nfs.man - man5_MANS = nfs.man - - sbin_PROGRAMS = mount.nfs --EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS) -+EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS) - mount_common = error.c network.c token.c \ - parse_opt.c parse_dev.c \ - nfsmount.c nfs4mount.c stropts.c\ - mount_constants.h error.h network.h token.h \ - parse_opt.h parse_dev.h \ -- nfs4_mount.h nfs_mount4.h stropts.h version.h \ -- mount_config.h utils.c utils.h -+ nfs4_mount.h stropts.h version.h \ -+ mount_config.h utils.c utils.h \ -+ nfs_mount.h - - if MOUNT_CONFIG - mount_common += configfile.c - man5_MANS += nfsmount.conf.man --EXTRA_DIST += nfsmount.conf -+else -+EXTRA_DIST += nfsmount.conf.man - endif - - mount_nfs_LDADD = ../../support/nfs/libnfs.a \ -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index 6f85dc9..fa46d54 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -174,7 +174,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - { - int rc, c; - char *spec = NULL, *opts = NULL; -- int ret = EX_FAIL; -+ int ret = EX_FAIL, verbose = 0; - - static const struct option longopts[] = { - { "force", 0, 0, 'f' }, -@@ -201,6 +201,8 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - return EX_USAGE; - } - -+ verbose = mnt_context_is_verbose(cxt); -+ - if (optind < argc) - spec = argv[optind++]; - -@@ -228,6 +230,10 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - goto err; - } - -+ if (verbose) -+ printf(_("%s: %s mount point detected\n"), spec, -+ mnt_context_get_fstype(cxt)); -+ - opts = retrieve_mount_options(mnt_context_get_fs(cxt)); - - if (!mnt_context_is_lazy(cxt)) { -@@ -263,6 +269,12 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - } - ret = EX_SUCCESS; - err: -+ if (verbose) { -+ if (ret == EX_SUCCESS) -+ printf(_("%s: umounted\n"), spec); -+ else -+ printf(_("%s: umount failed\n"), spec); -+ } - free(opts); - return ret; - } -diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am -index 7db968b..9e1ab5c 100644 ---- a/utils/mountd/Makefile.am -+++ b/utils/mountd/Makefile.am -@@ -7,6 +7,7 @@ RPCPREFIX = rpc. - KPREFIX = @kprefix@ - sbin_PROGRAMS = mountd - -+noinst_HEADERS = fsloc.h - mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \ - svc_run.c fsloc.c v4root.c mountd.h - mountd_LDADD = ../../support/export/libexport.a \ -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 663a52a..c23d384 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -61,15 +61,13 @@ enum nfsd_fsid { - * Record is terminated with newline. - * - */ --static int cache_export_ent(char *domain, struct exportent *exp, char *p); -+static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path); - - #define INITIAL_MANAGED_GROUPS 100 - --char *lbuf = NULL; --int lbuflen = 0; - extern int use_ipaddr; - --static void auth_unix_ip(FILE *f) -+static void auth_unix_ip(int f) - { - /* requests are - * class IP-ADDR -@@ -78,23 +76,26 @@ static void auth_unix_ip(FILE *f) - * - * "nfsd" IP-ADDR expiry domainname - */ -- char *cp; - char class[20]; - char ipaddr[INET6_ADDRSTRLEN + 1]; - char *client = NULL; - struct addrinfo *tmp = NULL; -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) -- return; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen; -+ -+ blen = read(f, buf, sizeof(buf)); -+ if (blen <= 0 || buf[blen-1] != '\n') return; -+ buf[blen-1] = 0; - -- xlog(D_CALL, "auth_unix_ip: inbuf '%s'", lbuf); -+ xlog(D_CALL, "auth_unix_ip: inbuf '%s'", buf); - -- cp = lbuf; -+ bp = buf; - -- if (qword_get(&cp, class, 20) <= 0 || -+ if (qword_get(&bp, class, 20) <= 0 || - strcmp(class, "nfsd") != 0) - return; - -- if (qword_get(&cp, ipaddr, sizeof(ipaddr) - 1) <= 0) -+ if (qword_get(&bp, ipaddr, sizeof(ipaddr) - 1) <= 0) - return; - - tmp = host_pton(ipaddr); -@@ -113,16 +114,20 @@ static void auth_unix_ip(FILE *f) - freeaddrinfo(ai); - } - } -- qword_print(f, "nfsd"); -- qword_print(f, ipaddr); -- qword_printtimefrom(f, DEFAULT_TTL); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, "nfsd"); -+ qword_add(&bp, &blen, ipaddr); -+ qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); - if (use_ipaddr) { - memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1); - ipaddr[0] = '$'; -- qword_print(f, ipaddr); -+ qword_add(&bp, &blen, ipaddr); - } else if (client) -- qword_print(f, *client?client:"DEFAULT"); -- qword_eol(f); -+ qword_add(&bp, &blen, *client?client:"DEFAULT"); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ xlog(L_ERROR, "auth_unix_ip: error writing reply"); -+ - xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); - - free(client); -@@ -130,7 +135,7 @@ static void auth_unix_ip(FILE *f) - - } - --static void auth_unix_gid(FILE *f) -+static void auth_unix_gid(int f) - { - /* Request are - * uid -@@ -144,7 +149,8 @@ static void auth_unix_gid(FILE *f) - gid_t *more_groups; - int ngroups; - int rv, i; -- char *cp; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen; - - if (groups_len == 0) { - groups = malloc(sizeof(gid_t) * INITIAL_MANAGED_GROUPS); -@@ -156,11 +162,12 @@ static void auth_unix_gid(FILE *f) - - ngroups = groups_len; - -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) -- return; -+ blen = read(f, buf, sizeof(buf)); -+ if (blen <= 0 || buf[blen-1] != '\n') return; -+ buf[blen-1] = 0; - -- cp = lbuf; -- if (qword_get_uint(&cp, &uid) != 0) -+ bp = buf; -+ if (qword_get_uint(&bp, &uid) != 0) - return; - - pw = getpwuid(uid); -@@ -180,15 +187,19 @@ static void auth_unix_gid(FILE *f) - } - } - } -- qword_printuint(f, uid); -- qword_printtimefrom(f, DEFAULT_TTL); -+ -+ bp = buf; blen = sizeof(buf); -+ qword_adduint(&bp, &blen, uid); -+ qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); - if (rv >= 0) { -- qword_printuint(f, ngroups); -+ qword_adduint(&bp, &blen, ngroups); - for (i=0; i 7) - goto out; /* unknown type */ -- if ((fsidlen = qword_get(&cp, fsid, 32)) <= 0) -+ if ((fsidlen = qword_get(&bp, fsid, 32)) <= 0) - goto out; - if (parse_fsid(fsidtype, fsidlen, fsid, &parsed)) - goto out; -@@ -796,12 +809,13 @@ static void nfsd_fh(FILE *f) - } - - if (found) -- if (cache_export_ent(dom, found, found_path) < 0) -+ if (cache_export_ent(buf, sizeof(buf), dom, found, found_path) < 0) - found = 0; - -- qword_print(f, dom); -- qword_printint(f, fsidtype); -- qword_printhex(f, fsid, fsidlen); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, dom); -+ qword_addint(&bp, &blen, fsidtype); -+ qword_addhex(&bp, &blen, fsid, fsidlen); - /* The fsid -> path lookup can be quite expensive as it - * potentially stats and reads lots of devices, and some of those - * might have spun-down. The Answer is not likely to -@@ -810,20 +824,21 @@ static void nfsd_fh(FILE *f) - * timeout. Maybe this should be configurable on the command - * line. - */ -- qword_printint(f, 0x7fffffff); -+ qword_addint(&bp, &blen, 0x7fffffff); - if (found) -- qword_print(f, found_path); -- qword_eol(f); -- out: -+ qword_add(&bp, &blen, found_path); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ xlog(L_ERROR, "nfsd_fh: error writing reply"); -+out: - if (found_path) - free(found_path); - freeaddrinfo(ai); - free(dom); - xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL); -- return; - } - --static void write_fsloc(FILE *f, struct exportent *ep) -+static void write_fsloc(char **bp, int *blen, struct exportent *ep) - { - struct servers *servers; - -@@ -833,20 +848,20 @@ static void write_fsloc(FILE *f, struct exportent *ep) - servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); - if (!servers) - return; -- qword_print(f, "fsloc"); -- qword_printint(f, servers->h_num); -+ qword_add(bp, blen, "fsloc"); -+ qword_addint(bp, blen, servers->h_num); - if (servers->h_num >= 0) { - int i; - for (i=0; ih_num; i++) { -- qword_print(f, servers->h_mp[i]->h_host); -- qword_print(f, servers->h_mp[i]->h_path); -+ qword_add(bp, blen, servers->h_mp[i]->h_host); -+ qword_add(bp, blen, servers->h_mp[i]->h_path); - } - } -- qword_printint(f, servers->h_referral); -+ qword_addint(bp, blen, servers->h_referral); - release_replicas(servers); - } - --static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) -+static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_mask) - { - struct sec_entry *p; - -@@ -857,45 +872,52 @@ static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) - return; - } - fix_pseudoflavor_flags(ep); -- qword_print(f, "secinfo"); -- qword_printint(f, p - ep->e_secinfo); -+ qword_add(bp, blen, "secinfo"); -+ qword_addint(bp, blen, p - ep->e_secinfo); - for (p = ep->e_secinfo; p->flav; p++) { -- qword_printint(f, p->flav->fnum); -- qword_printint(f, p->flags & flag_mask); -+ qword_addint(bp, blen, p->flav->fnum); -+ qword_addint(bp, blen, p->flags & flag_mask); - } - - } - --static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exp) -+static int dump_to_cache(int f, char *buf, int buflen, char *domain, char *path, struct exportent *exp) - { -- qword_print(f, domain); -- qword_print(f, path); -+ char *bp = buf; -+ int blen = buflen; -+ time_t now = time(0); -+ -+ qword_add(&bp, &blen, domain); -+ qword_add(&bp, &blen, path); - if (exp) { - int different_fs = strcmp(path, exp->e_path) != 0; - int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; - -- qword_printtimefrom(f, exp->e_ttl); -- qword_printint(f, exp->e_flags & flag_mask); -- qword_printint(f, exp->e_anonuid); -- qword_printint(f, exp->e_anongid); -- qword_printint(f, exp->e_fsid); -- write_fsloc(f, exp); -- write_secinfo(f, exp, flag_mask); -- if (exp->e_uuid == NULL || different_fs) { -- char u[16]; -- if (uuid_by_path(path, 0, 16, u)) { -- qword_print(f, "uuid"); -- qword_printhex(f, u, 16); -- } -- } else { -- char u[16]; -- get_uuid(exp->e_uuid, 16, u); -- qword_print(f, "uuid"); -- qword_printhex(f, u, 16); -- } -+ qword_adduint(&bp, &blen, now + exp->e_ttl); -+ qword_addint(&bp, &blen, exp->e_flags & flag_mask); -+ qword_addint(&bp, &blen, exp->e_anonuid); -+ qword_addint(&bp, &blen, exp->e_anongid); -+ qword_addint(&bp, &blen, exp->e_fsid); -+ write_fsloc(&bp, &blen, exp); -+ write_secinfo(&bp, &blen, exp, flag_mask); -+ if (exp->e_uuid == NULL || different_fs) { -+ char u[16]; -+ if (uuid_by_path(path, 0, 16, u)) { -+ qword_add(&bp, &blen, "uuid"); -+ qword_addhex(&bp, &blen, u, 16); -+ } -+ } else { -+ char u[16]; -+ get_uuid(exp->e_uuid, 16, u); -+ qword_add(&bp, &blen, "uuid"); -+ qword_addhex(&bp, &blen, u, 16); -+ } - } else -- qword_printtimefrom(f, DEFAULT_TTL); -- return qword_eol(f); -+ qword_adduint(&bp, &blen, now + DEFAULT_TTL); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0) return -1; -+ if (write(f, buf, bp - buf) != bp - buf) return -1; -+ return 0; - } - - static nfs_export * -@@ -1245,27 +1267,27 @@ static struct exportent *lookup_junction(char *dom, const char *pathname, - return exp; - } - --static void lookup_nonexport(FILE *f, char *dom, char *path, -+static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, - struct addrinfo *ai) - { - struct exportent *eep; - - eep = lookup_junction(dom, path, ai); -- dump_to_cache(f, dom, path, eep); -+ dump_to_cache(f, buf, buflen, dom, path, eep); - if (eep == NULL) - return; - exportent_release(eep); - free(eep); - } - #else /* !HAVE_NFS_PLUGIN_H */ --static void lookup_nonexport(FILE *f, char *dom, char *path, -+static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, - struct addrinfo *UNUSED(ai)) - { -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, buf, buflen, dom, path, NULL); - } - #endif /* !HAVE_NFS_PLUGIN_H */ - --static void nfsd_export(FILE *f) -+static void nfsd_export(int f) - { - /* requests are: - * domain path -@@ -1273,26 +1295,28 @@ static void nfsd_export(FILE *f) - * domain path expiry flags anonuid anongid fsid - */ - -- char *cp; - char *dom, *path; - nfs_export *found = NULL; - struct addrinfo *ai = NULL; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen; - -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) -- return; -+ blen = read(f, buf, sizeof(buf)); -+ if (blen <= 0 || buf[blen-1] != '\n') return; -+ buf[blen-1] = 0; - -- xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf); -+ xlog(D_CALL, "nfsd_export: inbuf '%s'", buf); - -- cp = lbuf; -- dom = malloc(strlen(cp)); -- path = malloc(strlen(cp)); -+ bp = buf; -+ dom = malloc(blen); -+ path = malloc(blen); - - if (!dom || !path) - goto out; - -- if (qword_get(&cp, dom, strlen(lbuf)) <= 0) -+ if (qword_get(&bp, dom, blen) <= 0) - goto out; -- if (qword_get(&cp, path, strlen(lbuf)) <= 0) -+ if (qword_get(&bp, path, blen) <= 0) - goto out; - - auth_reload(); -@@ -1306,14 +1330,14 @@ static void nfsd_export(FILE *f) - found = lookup_export(dom, path, ai); - - if (found) { -- if (dump_to_cache(f, dom, path, &found->m_export) < 0) { -+ if (dump_to_cache(f, buf, sizeof(buf), dom, path, &found->m_export) < 0) { - xlog(L_WARNING, - "Cannot export %s, possibly unsupported filesystem" - " or fsid= required", path); -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, buf, sizeof(buf), dom, path, NULL); - } - } else -- lookup_nonexport(f, dom, path, ai); -+ lookup_nonexport(f, buf, sizeof(buf), dom, path, ai); - - out: - xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); -@@ -1325,15 +1349,14 @@ static void nfsd_export(FILE *f) - - struct { - char *cache_name; -- void (*cache_handle)(FILE *f); -- FILE *f; -- char vbuf[RPC_CHAN_BUF_SIZE]; -+ void (*cache_handle)(int f); -+ int f; - } cachelist[] = { -- { "auth.unix.ip", auth_unix_ip, NULL, ""}, -- { "auth.unix.gid", auth_unix_gid, NULL, ""}, -- { "nfsd.export", nfsd_export, NULL, ""}, -- { "nfsd.fh", nfsd_fh, NULL, ""}, -- { NULL, NULL, NULL, ""} -+ { "auth.unix.ip", auth_unix_ip, -1 }, -+ { "auth.unix.gid", auth_unix_gid, -1 }, -+ { "nfsd.export", nfsd_export, -1 }, -+ { "nfsd.fh", nfsd_fh, -1 }, -+ { NULL, NULL, -1 } - }; - - extern int manage_gids; -@@ -1350,11 +1373,7 @@ void cache_open(void) - if (!manage_gids && cachelist[i].cache_handle == auth_unix_gid) - continue; - sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name); -- cachelist[i].f = fopen(path, "r+"); -- if (cachelist[i].f != NULL) { -- setvbuf(cachelist[i].f, cachelist[i].vbuf, _IOLBF, -- RPC_CHAN_BUF_SIZE); -- } -+ cachelist[i].f = open(path, O_RDWR); - } - } - -@@ -1366,8 +1385,8 @@ void cache_set_fds(fd_set *fdset) - { - int i; - for (i=0; cachelist[i].cache_name; i++) { -- if (cachelist[i].f) -- FD_SET(fileno(cachelist[i].f), fdset); -+ if (cachelist[i].f >= 0) -+ FD_SET(cachelist[i].f, fdset); - } - } - -@@ -1380,11 +1399,11 @@ int cache_process_req(fd_set *readfds) - int i; - int cnt = 0; - for (i=0; cachelist[i].cache_name; i++) { -- if (cachelist[i].f != NULL && -- FD_ISSET(fileno(cachelist[i].f), readfds)) { -+ if (cachelist[i].f >= 0 && -+ FD_ISSET(cachelist[i].f, readfds)) { - cnt++; - cachelist[i].cache_handle(cachelist[i].f); -- FD_CLR(fileno(cachelist[i].f), readfds); -+ FD_CLR(cachelist[i].f, readfds); - } - } - return cnt; -@@ -1397,14 +1416,14 @@ int cache_process_req(fd_set *readfds) - * % echo $domain $path $[now+DEFAULT_TTL] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel - */ - --static int cache_export_ent(char *domain, struct exportent *exp, char *path) -+static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path) - { -- int err; -- FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); -- if (!f) -- return -1; -+ int f, err; -+ -+ f = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); -+ if (f < 0) return -1; - -- err = dump_to_cache(f, domain, exp->e_path, exp); -+ err = dump_to_cache(f, buf, buflen, domain, exp->e_path, exp); - if (err) { - xlog(L_WARNING, - "Cannot export %s, possibly unsupported filesystem or" -@@ -1445,13 +1464,13 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) - continue; - dev = stb.st_dev; - path[l] = 0; -- dump_to_cache(f, domain, path, exp); -+ dump_to_cache(f, buf, buflen, domain, path, exp); - path[l] = c; - } - break; - } - -- fclose(f); -+ close(f); - return err; - } - -@@ -1462,27 +1481,25 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) - */ - int cache_export(nfs_export *exp, char *path) - { -- char buf[INET6_ADDRSTRLEN]; -- int err; -- FILE *f; -+ char ip[INET6_ADDRSTRLEN]; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen, f; - -- f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w"); -- if (!f) -+ f = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); -+ if (f < 0) - return -1; - -- -- qword_print(f, "nfsd"); -- qword_print(f, -- host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); -- qword_printtimefrom(f, exp->m_export.e_ttl); -- qword_print(f, exp->m_client->m_hostname); -- err = qword_eol(f); -- -- fclose(f); -- -- err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export, path) -- || err; -- return err; -+ bp = buf, blen = sizeof(buf); -+ qword_add(&bp, &blen, "nfsd"); -+ qword_add(&bp, &blen, host_ntop(get_addrlist(exp->m_client, 0), ip, sizeof(ip))); -+ qword_adduint(&bp, &blen, time(0) + exp->m_export.e_ttl); -+ qword_add(&bp, &blen, exp->m_client->m_hostname); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) blen = -1; -+ close(f); -+ if (blen < 0) return -1; -+ -+ return cache_export_ent(buf, sizeof(buf), exp->m_client->m_hostname, &exp->m_export, path); - } - - /** -@@ -1501,27 +1518,33 @@ int cache_export(nfs_export *exp, char *path) - struct nfs_fh_len * - cache_get_filehandle(nfs_export *exp, int len, char *p) - { -- FILE *f = fopen("/proc/fs/nfsd/filehandle", "r+"); -- char buf[200]; -- char *bp = buf; -- int failed; - static struct nfs_fh_len fh; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen, f; -+ -+ f = open("/proc/fs/nfsd/filehandle", O_RDWR); -+ if (f < 0) { -+ f = open("/proc/fs/nfs/filehandle", O_RDWR); -+ if (f < 0) return NULL; -+ } - -- if (!f) -- f = fopen("/proc/fs/nfs/filehandle", "r+"); -- if (!f) -+ bp = buf, blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->m_client->m_hostname); -+ qword_add(&bp, &blen, p); -+ qword_addint(&bp, &blen, len); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) { -+ close(f); - return NULL; -+ } -+ bp = buf; -+ blen = read(f, buf, sizeof(buf)); -+ close(f); - -- qword_print(f, exp->m_client->m_hostname); -- qword_print(f, p); -- qword_printint(f, len); -- failed = qword_eol(f); -- -- if (!failed) -- failed = (fgets(buf, sizeof(buf), f) == NULL); -- fclose(f); -- if (failed) -+ if (blen <= 0 || buf[blen-1] != '\n') - return NULL; -+ buf[blen-1] = 0; -+ - memset(fh.fh_handle, 0, sizeof(fh.fh_handle)); - fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); - return &fh; -diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am -index 1536065..39a6e6f 100644 ---- a/utils/nfsd/Makefile.am -+++ b/utils/nfsd/Makefile.am -@@ -7,6 +7,7 @@ RPCPREFIX = rpc. - KPREFIX = @kprefix@ - sbin_PROGRAMS = nfsd - -+noinst_HEADERS = nfssvc.h - nfsd_SOURCES = nfsd.c nfssvc.c - nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC) - -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 0675b6a..027e5ac 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - #include "nfslib.h" - #include "xlog.h" -diff --git a/utils/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am -index 7524295..0a2858f 100644 ---- a/utils/nfsdcltrack/Makefile.am -+++ b/utils/nfsdcltrack/Makefile.am -@@ -10,6 +10,8 @@ EXTRA_DIST = $(man8_MANS) - AM_CFLAGS += -D_LARGEFILE64_SOURCE - sbin_PROGRAMS = nfsdcltrack - -+noinst_HEADERS = sqlite.h -+ - nfsdcltrack_SOURCES = nfsdcltrack.c sqlite.c - nfsdcltrack_LDADD = ../../support/nfs/libnfs.a $(LIBSQLITE) $(LIBCAP) - -diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c -index fb45c4a..54cd748 100644 ---- a/utils/nfsdcltrack/sqlite.c -+++ b/utils/nfsdcltrack/sqlite.c -@@ -102,7 +102,7 @@ sqlite_query_schema_version(void) - -1, &stmt, NULL); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "Unable to prepare select statement: %s", -- sqlite3_errstr(ret)); -+ sqlite3_errmsg(dbh)); - ret = 0; - goto out; - } -@@ -111,7 +111,7 @@ sqlite_query_schema_version(void) - ret = sqlite3_step(stmt); - if (ret != SQLITE_ROW) { - xlog(L_ERROR, "Select statement execution failed: %s", -- sqlite3_errstr(ret)); -+ sqlite3_errmsg(dbh)); - ret = 0; - goto out; - } -@@ -324,7 +324,7 @@ sqlite_prepare_dbh(const char *topdir) - ret = sqlite3_busy_timeout(dbh, CLTRACK_SQLITE_BUSY_TIMEOUT); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "Unable to set sqlite busy timeout: %s", -- sqlite3_errstr(ret)); -+ sqlite3_errmsg(dbh)); - goto out_close; - } - -@@ -357,7 +357,7 @@ sqlite_prepare_dbh(const char *topdir) - - return ret; - out_close: -- sqlite3_close_v2(dbh); -+ sqlite3_close(dbh); - dbh = NULL; - return ret; - } -@@ -574,21 +574,21 @@ sqlite_query_reclaiming(const time_t grace_start) - "time < ? OR has_session != 1", -1, &stmt, NULL); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "%s: unable to prepare select statement: %s", -- __func__, sqlite3_errstr(ret)); -+ __func__, sqlite3_errmsg(dbh)); - return ret; - } - - ret = sqlite3_bind_int64(stmt, 1, (sqlite3_int64)grace_start); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "%s: bind int64 failed: %s", -- __func__, sqlite3_errstr(ret)); -+ __func__, sqlite3_errmsg(dbh)); - return ret; - } - - ret = sqlite3_step(stmt); - if (ret != SQLITE_ROW) { - xlog(L_ERROR, "%s: unexpected return code from select: %s", -- __func__, sqlite3_errstr(ret)); -+ __func__, sqlite3_errmsg(dbh)); - return ret; - } - -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index 737a219..91cedfd 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -7,4 +7,4 @@ nfsidmap_SOURCES = nfsidmap.c - nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in --EXTRA_DIST = id_resolver.conf -+EXTRA_DIST = id_resolver.conf $(man8_MANS) -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index e0d31e7..5d62078 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -25,7 +25,7 @@ char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; - - #define PROCKEYS "/proc/keys" - #ifndef DEFAULT_KEYRING --#define DEFAULT_KEYRING "id_resolver" -+#define DEFAULT_KEYRING ".id_resolver" - #endif - - #ifndef PATH_IDMAPDCONF -@@ -209,10 +209,23 @@ static int key_invalidate(char *keystr, int keymask) - *(strchr(buf, ' ')) = '\0'; - sscanf(buf, "%x", &key); - -- if (keyctl_invalidate(key) < 0) { -- xlog_err("keyctl_invalidate(0x%x) failed: %m", key); -- fclose(fp); -- return 1; -+/* older libkeyutils compatibility */ -+#ifndef KEYCTL_INVALIDATE -+#define KEYCTL_INVALIDATE 21 /* invalidate a key */ -+#endif -+ if (keyctl(KEYCTL_INVALIDATE, key) < 0) { -+ if (errno != EOPNOTSUPP) { -+ xlog_err("keyctl_invalidate(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } else { -+ /* older kernel compatibility attempt: */ -+ if (keyctl_revoke(key) < 0) { -+ xlog_err("keyctl_revoke(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ } - } - - keymask &= ~mask; -@@ -316,6 +329,9 @@ int main(int argc, char **argv) - key, type, value, timeout); - } - -+ /* Become a possesor of the to-be-instantiated key to set the key's timeout */ -+ request_key("keyring", DEFAULT_KEYRING, NULL, KEY_SPEC_THREAD_KEYRING); -+ - if (strcmp(type, "uid") == 0) - rc = id_lookup(value, key, USER); - else if (strcmp(type, "gid") == 0) -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index 18e4d27..9f481db 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -558,7 +558,7 @@ print_server_stats(int opt_prt) - ; - } else { - print_numbers(LABEL_srvrpc -- "calls badcalls badclnt badauth xdrcall\n", -+ "calls badcalls badfmt badauth badclnt\n", - srvrpcinfo, 5); - printf("\n"); - } -diff --git a/utils/osd_login/Makefile.am b/utils/osd_login/Makefile.am -index 20c2d8c..ded1fd3 100644 ---- a/utils/osd_login/Makefile.am -+++ b/utils/osd_login/Makefile.am -@@ -4,6 +4,6 @@ - # overridden at config time. - sbindir = /sbin - --sbin_SCRIPTS = osd_login -+dist_sbin_SCRIPTS = osd_login - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am -index dc2bfc4..152b680 100644 ---- a/utils/statd/Makefile.am -+++ b/utils/statd/Makefile.am -@@ -8,7 +8,7 @@ sbin_PROGRAMS = statd sm-notify - dist_sbin_SCRIPTS = start-statd - statd_SOURCES = callback.c notlist.c misc.c monitor.c hostname.c \ - simu.c stat.c statd.c svc_run.c rmtcall.c \ -- notlist.h statd.h system.h version.h -+ notlist.h statd.h system.h - sm_notify_SOURCES = sm-notify.c - - BUILT_SOURCES = $(GENFILES) -@@ -20,7 +20,7 @@ sm_notify_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ - $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - --EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c -+EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c - - if CONFIG_RPCGEN - RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen diff --git a/nfs-utils-1.3.2.rc5.patch b/nfs-utils-1.3.2.rc5.patch deleted file mode 100644 index bbbb22f..0000000 --- a/nfs-utils-1.3.2.rc5.patch +++ /dev/null @@ -1,3516 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index 5824adc..4a2edc6 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -2,41 +2,13 @@ - - AUTOMAKE_OPTIONS = foreign - --SUBDIRS = tools support utils linux-nfs tests -+SUBDIRS = tools support utils linux-nfs tests systemd - - MAINTAINERCLEANFILES = Makefile.in - - EXTRA_DIST = \ - autogen.sh \ - \ -- debian/changelog \ -- debian/control \ -- debian/copyright \ -- debian/etc.exports \ -- debian/idmapd.conf \ -- debian/nfs-common.conffiles \ -- debian/nfs-common.default \ -- debian/nfs-common.dirs \ -- debian/nfs-common.files \ -- debian/nfs-common.init \ -- debian/nfs-common.install \ -- debian/nfs-common.postinst \ -- debian/nfs-common.postrm \ -- debian/nfs-common.prerm \ -- debian/nfs-kernel-server.NEWS \ -- debian/nfs-kernel-server.conffiles \ -- debian/nfs-kernel-server.default \ -- debian/nfs-kernel-server.dirs \ -- debian/nfs-kernel-server.init \ -- debian/nfs-kernel-server.postinst \ -- debian/nfs-kernel-server.postrm \ -- debian/nfs-kernel-server.prerm \ -- debian/nhfsstone.dirs \ -- debian/nhfsstone.files \ -- debian/nhfsstone.postinst \ -- debian/nhfsstone.prerm \ -- debian/rules \ -- \ - aclocal/bsdsignals.m4 \ - aclocal/nfs-utils.m4 \ - aclocal/kerberos5.m4 \ -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index b823364..ebc1bea 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -2,61 +2,18 @@ dnl Checks for TI-RPC library and headers - dnl - AC_DEFUN([AC_LIBTIRPC], [ - -- AC_ARG_WITH([tirpcinclude], -- [AC_HELP_STRING([--with-tirpcinclude=DIR], -- [use TI-RPC headers in DIR])], -- [tirpc_header_dir=$withval], -- [tirpc_header_dir=/usr/include/tirpc]) -- -- dnl if --enable-tirpc was specifed, the following components -- dnl must be present, and we set up HAVE_ macros for them. -- -- if test "$enable_tirpc" != "no"; then -- -- dnl look for the library -- AC_CHECK_LIB([tirpc], [clnt_tli_create], [:], -- [if test "$enable_tirpc" = "yes"; then -- AC_MSG_ERROR([libtirpc not found.]) -- else -- AC_MSG_WARN([libtirpc not found. TIRPC disabled!]) -- enable_tirpc="no" -- fi]) -- fi -- -- if test "$enable_tirpc" != "no"; then -- -- dnl Check if library contains authgss_free_private_data -- AC_CHECK_LIB([tirpc], [authgss_free_private_data], [have_free_private_data=yes], -- [have_free_private_data=no]) -- fi -- -- if test "$enable_tirpc" != "no"; then -- dnl also must have the headers installed where we expect -- dnl look for headers; add -I compiler option if found -- AC_CHECK_HEADERS([${tirpc_header_dir}/netconfig.h], -- AC_SUBST([AM_CPPFLAGS], ["-I${tirpc_header_dir}"]), -- [if test "$enable_tirpc" = "yes"; then -- AC_MSG_ERROR([libtirpc headers not found.]) -- else -- AC_MSG_WARN([libtirpc headers not found. TIRPC disabled!]) -- enable_tirpc="no" -- fi]) -- -- fi -- -- dnl now set $LIBTIRPC accordingly -- if test "$enable_tirpc" != "no"; then -- AC_DEFINE([HAVE_LIBTIRPC], 1, -- [Define to 1 if you have and wish to use libtirpc.]) -- LIBTIRPC="-ltirpc" -- if test "$have_free_private_data" = "yes"; then -- AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1, -- [Define to 1 if your rpcsec library provides authgss_free_private_data,]) -- fi -- else -- LIBTIRPC="" -- fi -- -+ PKG_PROG_PKG_CONFIG([0.9.0]) -+ AS_IF( -+ [test "$enable_tirpc" != "no"], -+ [PKG_CHECK_MODULES([TIRPC], [libtirpc >= 0.2.4], -+ [LIBTIRPC="${TIRPC_LIBS}" -+ AM_CPPFLAGS="${AM_CPPFLAGS} ${TIRPC_CFLAGS}" -+ AC_DEFINE([HAVE_LIBTIRPC], [1], -+ [Define to 1 if you have and wish to use libtirpc.])], -+ [AS_IF([test "$enable_tirpc" != "no"], [AC_MSG_ERROR([libtirpc not found.])], -+ [LIBTIRPC=""])])]) -+ -+ AC_SUBST([AM_CPPFLAGS]) - AC_SUBST(LIBTIRPC) - - ])dnl -diff --git a/configure.ac b/configure.ac -index 59fd14d..a8b1fc3 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -55,6 +55,16 @@ AC_ARG_WITH(start-statd, - ) - AC_SUBST(startstatd) - AC_DEFINE_UNQUOTED(START_STATD, "$startstatd", [Define this to a script which can start statd on mount]) -+unitdir=/usr/lib/systemd/system -+AC_ARG_WITH(systemd, -+ [AC_HELP_STRING([--with-systemd@<:@=unit-dir-path@:>@], -+ [install systemd unit files @<:@Default: no, and path defaults to /usr/lib/systemd/system if not given@:>@])], -+ test "$withval" = "no" && use_systemd=0 || unitdir=$withval use_systemd=1 -+ use_systemd=0 -+ ) -+ AM_CONDITIONAL(INSTALL_SYSTEMD, [test "$use_systemd" = 1]) -+ AC_SUBST(unitdir) -+ - AC_ARG_ENABLE(nfsv4, - [AC_HELP_STRING([--enable-nfsv4], - [enable support for NFSv4 @<:@default=yes@:>@])], -@@ -108,10 +118,8 @@ AC_ARG_ENABLE(svcgss, - [enable building svcgssd for rpcsec_gss server support @<:@default=yes@:>@])], - enable_svcgss=$enableval, - enable_svcgss=yes) -- if test "$enable_gss" = yes; then -- if "enable_svcgss" = yes; then -- SVCGSSD=svcgssd -- fi -+ if test "$enable_gss" = yes -a "$enable_svcgss" = yes; then -+ SVCGSSD=svcgssd - else - enable_svcgss= - SVCGSSD= -@@ -518,6 +526,7 @@ AC_CONFIG_FILES([ - utils/showmount/Makefile - utils/statd/Makefile - utils/osd_login/Makefile -+ systemd/Makefile - tests/Makefile - tests/nsm_client/Makefile]) - AC_OUTPUT -diff --git a/support/export/client.c b/support/export/client.c -index f85e11c..95156f0 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -277,7 +277,7 @@ client_lookup(char *hname, int canonical) - if (htype == MCL_FQDN && !canonical) { - ai = host_addrinfo(hname); - if (!ai) { -- xlog(L_ERROR, "Failed to resolve %s", hname); -+ xlog(L_WARNING, "Failed to resolve %s", hname); - goto out; - } - hname = ai->ai_canonname; -diff --git a/support/export/export.c b/support/export/export.c -index 6b1d045..e1bebce 100644 ---- a/support/export/export.c -+++ b/support/export/export.c -@@ -69,22 +69,30 @@ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep) - * export_read - read entries from /etc/exports - * @fname: name of file to read from - * -+ * Returns number of read entries. - */ --void -+int - export_read(char *fname) - { - struct exportent *eep; - nfs_export *exp; - -+ int volumes = 0; -+ - setexportent(fname, "r"); - while ((eep = getexportent(0,1)) != NULL) { - exp = export_lookup(eep->e_hostname, eep->e_path, 0); -- if (!exp) -- export_create(eep, 0); -+ if (!exp) { -+ if (export_create(eep, 0)) -+ /* possible complaints already logged */ -+ volumes++; -+ } - else - warn_duplicated_exports(exp, eep); - } - endexportent(); -+ -+ return volumes; - } - - /** -diff --git a/support/export/hostname.c b/support/export/hostname.c -index d9153e1..169baa5 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -177,11 +177,11 @@ host_addrinfo(const char *hostname) - case 0: - return ai; - case EAI_SYSTEM: -- xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m", -+ xlog(D_PARSE, "%s: failed to resolve %s: (%d) %m", - __func__, hostname, errno); - break; - default: -- xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ xlog(D_PARSE, "%s: failed to resolve %s: %s", - __func__, hostname, gai_strerror(error)); - break; - } -diff --git a/support/include/Makefile.am b/support/include/Makefile.am -index 4b33ee9..5c80c8b 100644 ---- a/support/include/Makefile.am -+++ b/support/include/Makefile.am -@@ -3,6 +3,7 @@ - SUBDIRS = nfs rpcsvc sys - - noinst_HEADERS = \ -+ cld.h \ - exportfs.h \ - ha-callout.h \ - misc.h \ -@@ -10,9 +11,13 @@ noinst_HEADERS = \ - nfs_paths.h \ - nfslib.h \ - nfsrpc.h \ -+ nls.h \ - nsm.h \ -+ pseudoflavors.h \ - rpcmisc.h \ -+ sockaddr.h \ - tcpwrapper.h \ -+ v4root.h \ - xio.h \ - xlog.h \ - xmalloc.h \ -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 9021fae..4cac203 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -10,6 +10,7 @@ - #define EXPORTFS_H - - #include -+#include - - #include "sockaddr.h" - #include "nfslib.h" -@@ -133,7 +134,7 @@ struct addrinfo * client_resolve(const struct sockaddr *sap); - int client_member(const char *client, - const char *name); - --void export_read(char *fname); -+int export_read(char *fname); - void export_reset(nfs_export *); - nfs_export * export_lookup(char *hname, char *path, int caconical); - nfs_export * export_find(const struct addrinfo *ai, -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index ce4b14b..c5dc6f8 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -152,11 +152,6 @@ struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path); - struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin, - const char *path, int const size); - --void qword_print(FILE *f, char *str); --void qword_printhex(FILE *f, char *str, int slen); --void qword_printint(FILE *f, int num); --int qword_eol(FILE *f); --int readline(int fd, char **buf, int *lenp); - int qword_get(char **bpp, char *dest, int bufsize); - int qword_get_int(char **bpp, int *anint); - void cache_flush(int force); -@@ -167,13 +162,12 @@ void qword_addint(char **bpp, int *lp, int n); - void qword_adduint(char **bpp, int *lp, unsigned int n); - void qword_addeol(char **bpp, int *lp); - int qword_get_uint(char **bpp, unsigned int *anint); --void qword_printuint(FILE *f, unsigned int num); --void qword_printtimefrom(FILE *f, unsigned int num); - - void closeall(int min); - - int svctcp_socket (u_long __number, int __reuse); - int svcudp_socket (u_long __number); -+int svcsock_nonblock (int __sock); - - /* Misc shared code prototypes */ - size_t strlcat(char *, const char *, size_t); -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index 1bfae7a..fbbdb6a 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -23,6 +23,7 @@ - #ifndef __NFS_UTILS_NFSRPC_H - #define __NFS_UTILS_NFSRPC_H - -+#include - #include - #include - -diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c -index 61e07a8..42e2502 100644 ---- a/support/nfs/cacheio.c -+++ b/support/nfs/cacheio.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -120,74 +121,6 @@ void qword_addeol(char **bpp, int *lp) - (*lp)--; - } - --static char qword_buf[8192]; --void qword_print(FILE *f, char *str) --{ -- char *bp = qword_buf; -- int len = sizeof(qword_buf); -- qword_add(&bp, &len, str); -- if (fwrite(qword_buf, bp-qword_buf, 1, f) != 1) { -- xlog_warn("qword_print: fwrite failed: errno %d (%s)", -- errno, strerror(errno)); -- } --} -- --void qword_printhex(FILE *f, char *str, int slen) --{ -- char *bp = qword_buf; -- int len = sizeof(qword_buf); -- qword_addhex(&bp, &len, str, slen); -- if (fwrite(qword_buf, bp-qword_buf, 1, f) != 1) { -- xlog_warn("qword_printhex: fwrite failed: errno %d (%s)", -- errno, strerror(errno)); -- } --} -- --void qword_printint(FILE *f, int num) --{ -- fprintf(f, "%d ", num); --} -- --void qword_printuint(FILE *f, unsigned int num) --{ -- fprintf(f, "%u ", num); --} -- --void qword_printtimefrom(FILE *f, unsigned int num) --{ -- fprintf(f, "%lu ", time(0) + num); --} -- --int qword_eol(FILE *f) --{ -- int err; -- -- err = fprintf(f,"\n"); -- if (err < 0) { -- xlog_warn("qword_eol: fprintf failed: errno %d (%s)", -- errno, strerror(errno)); -- } else { -- err = fflush(f); -- if (err) { -- xlog_warn("qword_eol: fflush failed: errno %d (%s)", -- errno, strerror(errno)); -- } -- } -- /* -- * We must send one line (and one line only) in a single write -- * call. In case of a write error, libc may accumulate the -- * unwritten data and try to write it again later, resulting in a -- * multi-line write. So we must explicitly ask it to throw away -- * any such cached data. But we return any original error -- * indication to the caller. -- */ -- __fpurge(f); -- fflush(f); -- return err; --} -- -- -- - #define isodigit(c) (isdigit(c) && c <= '7') - int qword_get(char **bpp, char *dest, int bufsize) - { -@@ -265,48 +198,6 @@ int qword_get_uint(char **bpp, unsigned int *anint) - return 0; - } - --#define READLINE_BUFFER_INCREMENT 2048 -- --int readline(int fd, char **buf, int *lenp) --{ -- /* read a line into *buf, which is malloced *len long -- * realloc if needed until we find a \n -- * nul out the \n and return -- * 0 on eof, 1 on success -- */ -- int len; -- -- if (*lenp == 0) { -- char *b = malloc(READLINE_BUFFER_INCREMENT); -- if (b == NULL) -- return 0; -- *buf = b; -- *lenp = READLINE_BUFFER_INCREMENT; -- } -- len = read(fd, *buf, *lenp); -- if (len <= 0) -- return 0; -- while ((*buf)[len-1] != '\n') { -- /* now the less common case. There was no newline, -- * so we have to keep reading after re-alloc -- */ -- char *new; -- int nl; -- *lenp += READLINE_BUFFER_INCREMENT; -- new = realloc(*buf, *lenp); -- if (new == NULL) -- return 0; -- *buf = new; -- nl = read(fd, *buf + len, *lenp - len); -- if (nl <= 0) -- return 0; -- len += nl; -- } -- (*buf)[len-1] = '\0'; -- return 1; --} -- -- - /* Check if we should use the new caching interface - * This succeeds iff the "nfsd" filesystem is mounted on - * /proc/fs/nfs -diff --git a/support/nfs/nfsexport.c b/support/nfs/nfsexport.c -index f129fd2..afd7c90 100644 ---- a/support/nfs/nfsexport.c -+++ b/support/nfs/nfsexport.c -@@ -18,6 +18,7 @@ - #include - - #include "nfslib.h" -+#include "misc.h" - - /* if /proc/net/rpc/... exists, then - * write to it, as that interface is more stable. -@@ -32,62 +33,72 @@ - static int - exp_unexp(struct nfsctl_export *exp, int export) - { -- FILE *f; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; - struct stat stb; - __u32 fsid; - char fsidstr[8]; - __u16 dev; - __u32 inode; -- int err; -+ int err = 0, f, blen; - -+ f = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); -+ if (f < 0) return -1; - -- f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); -- if (f == NULL) return -1; -- qword_print(f, exp->ex_client); -- qword_print(f, exp->ex_path); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->ex_client); -+ qword_add(&bp, &blen, exp->ex_path); - if (export) { -- qword_printint(f, 0x7fffffff); -- qword_printint(f, exp->ex_flags); -- qword_printint(f, exp->ex_anon_uid); -- qword_printint(f, exp->ex_anon_gid); -- qword_printint(f, exp->ex_dev); -+ qword_addint(&bp, &blen, 0x7fffffff); -+ qword_addint(&bp, &blen, exp->ex_flags); -+ qword_addint(&bp, &blen, exp->ex_anon_uid); -+ qword_addint(&bp, &blen, exp->ex_anon_gid); -+ qword_addint(&bp, &blen, exp->ex_dev); - } else -- qword_printint(f, 1); -- -- err = qword_eol(f); -- fclose(f); -+ qword_addint(&bp, &blen, 1); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ err = -1; -+ close(f); - - if (stat(exp->ex_path, &stb) != 0) - return -1; -- f = fopen("/proc/net/rpc/nfsd.fh/channel", "w"); -- if (f==NULL) return -1; -+ -+ f = open("/proc/net/rpc/nfsd.fh/channel", O_WRONLY); -+ if (f < 0) return -1; - if (exp->ex_flags & NFSEXP_FSID) { -- qword_print(f,exp->ex_client); -- qword_printint(f,1); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->ex_client); -+ qword_addint(&bp, &blen, 1); - fsid = exp->ex_dev; -- qword_printhex(f, (char*)&fsid, 4); -+ qword_addhex(&bp, &blen, (char*)&fsid, 4); - if (export) { -- qword_printint(f, 0x7fffffff); -- qword_print(f, exp->ex_path); -+ qword_addint(&bp, &blen, 0x7fffffff); -+ qword_add(&bp, &blen, exp->ex_path); - } else -- qword_printint(f, 1); -- -- err = qword_eol(f) || err; -+ qword_addint(&bp, &blen, 1); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ err = -1; - } -- qword_print(f,exp->ex_client); -- qword_printint(f,0); -+ -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->ex_client); -+ qword_addint(&bp, &blen, 0); - dev = htons(major(stb.st_dev)); memcpy(fsidstr, &dev, 2); - dev = htons(minor(stb.st_dev)); memcpy(fsidstr+2, &dev, 2); - inode = stb.st_ino; memcpy(fsidstr+4, &inode, 4); - -- qword_printhex(f, fsidstr, 8); -+ qword_addhex(&bp, &blen, fsidstr, 8); - if (export) { -- qword_printint(f, 0x7fffffff); -- qword_print(f, exp->ex_path); -+ qword_addint(&bp, &blen, 0x7fffffff); -+ qword_add(&bp, &blen, exp->ex_path); - } else -- qword_printint(f, 1); -- err = qword_eol(f) || err; -- fclose(f); -+ qword_addint(&bp, &blen, 1); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ err = -1; -+ close(f); -+ - return err; - } - -diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c -index 64c98ff..ae2c0a6 100644 ---- a/support/nfs/rpcmisc.c -+++ b/support/nfs/rpcmisc.c -@@ -104,7 +104,7 @@ makesock(int port, int proto) - return -1; - } - -- return sock; -+ return svcsock_nonblock(sock); - } - - void -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index a706f87..5cb5ff6 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -49,6 +49,8 @@ - - #ifdef HAVE_LIBTIRPC - -+#include -+ - #define SVC_CREATE_XPRT_CACHE_SIZE (8) - static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; - -@@ -277,6 +279,12 @@ svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - "(%s, %u, %s)", name, version, nconf->nc_netid); - return 0; - } -+ if (svcsock_nonblock(xprt->xp_fd) < 0) { -+ /* close() already done by svcsock_nonblock() */ -+ xprt->xp_fd = RPC_ANYFD; -+ SVC_DESTROY(xprt); -+ return 0; -+ } - - if (!svc_reg(xprt, program, version, dispatch, nconf)) { - /* svc_reg(3) destroys @xprt in this case */ -@@ -332,6 +340,7 @@ svc_create_nconf_fixed_port(const char *name, const rpcprog_t program, - int fd; - - fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); -+ fd = svcsock_nonblock(fd); - if (fd == -1) - goto out_free; - -@@ -394,6 +403,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, - const struct sigaction create_sigaction = { - .sa_handler = SIG_IGN, - }; -+ int maxrec = RPC_MAXDATASIZE; - unsigned int visible, up, servport; - struct netconfig *nconf; - void *handlep; -@@ -405,6 +415,20 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, - */ - (void)sigaction(SIGPIPE, &create_sigaction, NULL); - -+ /* -+ * Setting MAXREC also enables non-blocking mode for tcp connections. -+ * This avoids DOS attacks by a client sending many requests but never -+ * reading the reply: -+ * - if a second request already is present for reading in the socket, -+ * after the first request just was read, libtirpc will break the -+ * connection. Thus an attacker can't simply send requests as fast as -+ * he can without waiting for the response. -+ * - if the write buffer of the socket is full, the next write() will -+ * fail with EAGAIN. libtirpc will retry the write in a loop for max. -+ * 2 seconds. If write still fails, the connection will be closed. -+ */ -+ rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); -+ - handlep = setnetconfig(); - if (handlep == NULL) { - xlog(L_ERROR, "Failed to access local netconfig database: %s", -diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c -index 74273b9..99321e7 100644 ---- a/support/nfs/svc_socket.c -+++ b/support/nfs/svc_socket.c -@@ -76,6 +76,39 @@ int getservport(u_long number, const char *proto) - return 0; - } - -+int -+svcsock_nonblock(int sock) -+{ -+ int flags; -+ -+ if (sock < 0) -+ return sock; -+ -+ /* This socket might be shared among multiple processes -+ * if mountd is run multi-threaded. So it is safest to -+ * make it non-blocking, else all threads might wake -+ * one will get the data, and the others will block -+ * indefinitely. -+ * In all cases, transaction on this socket are atomic -+ * (accept for TCP, packet-read and packet-write for UDP) -+ * so O_NONBLOCK will not confuse unprepared code causing -+ * it to corrupt messages. -+ * It generally safest to have O_NONBLOCK when doing an accept -+ * as if we get a RST after the SYN and before accept runs, -+ * we can block despite being told there was an acceptable -+ * connection. -+ */ -+ if ((flags = fcntl(sock, F_GETFL)) < 0) -+ perror(_("svc_socket: can't get socket flags")); -+ else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -+ perror(_("svc_socket: can't set socket flags")); -+ else -+ return sock; -+ -+ (void) __close(sock); -+ return -1; -+} -+ - static int - svc_socket (u_long number, int type, int protocol, int reuse) - { -@@ -113,38 +146,7 @@ svc_socket (u_long number, int type, int protocol, int reuse) - sock = -1; - } - -- if (sock >= 0) -- { -- /* This socket might be shared among multiple processes -- * if mountd is run multi-threaded. So it is safest to -- * make it non-blocking, else all threads might wake -- * one will get the data, and the others will block -- * indefinitely. -- * In all cases, transaction on this socket are atomic -- * (accept for TCP, packet-read and packet-write for UDP) -- * so O_NONBLOCK will not confuse unprepared code causing -- * it to corrupt messages. -- * It generally safest to have O_NONBLOCK when doing an accept -- * as if we get a RST after the SYN and before accept runs, -- * we can block despite being told there was an acceptable -- * connection. -- */ -- int flags; -- if ((flags = fcntl(sock, F_GETFL)) < 0) -- { -- perror (_("svc_socket: can't get socket flags")); -- (void) __close (sock); -- sock = -1; -- } -- else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) -- { -- perror (_("svc_socket: can't set socket flags")); -- (void) __close (sock); -- sock = -1; -- } -- } -- -- return sock; -+ return svcsock_nonblock(sock); - } - - /* -diff --git a/systemd/Makefile.am b/systemd/Makefile.am -new file mode 100644 -index 0000000..16cf5e6 ---- /dev/null -+++ b/systemd/Makefile.am -@@ -0,0 +1,32 @@ -+## Process this file with automake to produce Makefile.in -+ -+MAINTAINERCLEANFILES = Makefile.in -+ -+unit_files = \ -+ nfs-blkmap.target \ -+ nfs-client.target \ -+ \ -+ auth-rpcgss-module.service \ -+ nfs-blkmap.service \ -+ nfs-config.service \ -+ nfs-idmapd.service \ -+ nfs-mountd.service \ -+ nfs-server.service \ -+ nfs-utils.service \ -+ rpc-gssd.service \ -+ rpc-statd-notify.service \ -+ rpc-statd.service \ -+ rpc-svcgssd.service \ -+ \ -+ proc-fs-nfsd.mount \ -+ var-lib-nfs-rpc_pipefs.mount -+ -+EXTRA_DIST = $(unit_files) -+ -+unit_dir = /usr/lib/systemd/system -+ -+if INSTALL_SYSTEMD -+install-data-hook: $(unit_files) -+ mkdir -p $(DESTDIR)/$(unitdir) -+ cp $(unit_files) $(DESTDIR)/$(unitdir) -+endif -diff --git a/systemd/auth-rpcgss-module.service b/systemd/auth-rpcgss-module.service -index 3fc2f4a..0355e13 100644 ---- a/systemd/auth-rpcgss-module.service -+++ b/systemd/auth-rpcgss-module.service -@@ -6,7 +6,8 @@ - # unit will fail. But that's OK.) - [Unit] - Description=Kernel Module supporting RPCSEC_GSS --Before=gssproxy.service rpc-svcgssd.service -+Before=gssproxy.service rpc-svcgssd.service rpc-gssd.service -+Wants=gssproxy.service rpc-svcgssd.service rpc-gssd.service - ConditionPathExists=/etc/krb5.keytab - - [Service] -diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service -index 68cc9e9..f470e3d 100644 ---- a/systemd/nfs-blkmap.service -+++ b/systemd/nfs-blkmap.service -@@ -13,4 +13,4 @@ PartOf=nfs-utils.service - [Service] - Type=forking - PIDFile=/var/run/blkmapd.pid --ExecStart=/usr/sbin/blkmapd -+ExecStart=/usr/sbin/blkmapd $BLKMAPDARGS -diff --git a/systemd/nfs-client.target b/systemd/nfs-client.target -index 474f5e9..9b792a3 100644 ---- a/systemd/nfs-client.target -+++ b/systemd/nfs-client.target -@@ -5,9 +5,12 @@ Wants=remote-fs-pre.target - - # Note: we don't "Wants=rpc-statd.service" as "mount.nfs" will arrange to - # start that on demand if needed. --Wants=rpc-gssd.service rpc-svcgssd.service auth-rpcgss-module.service - Wants=nfs-blkmap.service rpc-statd-notify.service --Before=rpc-gssd.service rpc-svcgssd.service nfs-blkmap.service -+After=nfs-blkmap.service -+ -+# GSS services dependencies and ordering -+Wants=auth-rpcgss-module.service -+After=rpc-gssd.service rpc-svcgssd.service gssproxy.service - - [Install] - WantedBy=multi-user.target -diff --git a/systemd/nfs-idmapd.service b/systemd/nfs-idmapd.service -index 11895e2..726038d 100644 ---- a/systemd/nfs-idmapd.service -+++ b/systemd/nfs-idmapd.service -@@ -1,7 +1,7 @@ - [Unit] - Description=NFSv4 ID-name mapping service - --PartOf=nfs-utils.service -+BindsTo=nfs-server.service - - Wants=nfs-config.service - After=nfs-config.service -diff --git a/systemd/nfs-mountd.service b/systemd/nfs-mountd.service -index 7ccc0f7..d908afe 100644 ---- a/systemd/nfs-mountd.service -+++ b/systemd/nfs-mountd.service -@@ -3,8 +3,7 @@ Description=NFS Mount Daemon - Requires=proc-fs-nfsd.mount - After=proc-fs-nfsd.mount - After=network.target --PartOf=nfs-server.service --PartOf=nfs-utils.service -+BindsTo=nfs-server.service - - Wants=nfs-config.service - After=nfs-config.service -diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service -index 1048c5c..8010aad 100644 ---- a/systemd/nfs-server.service -+++ b/systemd/nfs-server.service -@@ -2,15 +2,17 @@ - Description=NFS server and services - Requires= network.target proc-fs-nfsd.mount rpcbind.target - Requires= nfs-mountd.service --Wants=rpc-statd.service nfs-idmapd.service auth-rpcgss-module.service --Wants=rpc-gssd.service gssproxy.service rpc-svcgssd.service -+Wants=rpc-statd.service nfs-idmapd.service - Wants=rpc-statd-notify.service - - After= network.target proc-fs-nfsd.mount rpcbind.target nfs-mountd.service - After= nfs-idmapd.service rpc-statd.service --After= rpc-gssd.service gssproxy.service rpc-svcgssd.service - Before= rpc-statd-notify.service - -+# GSS services dependencies and ordering -+Wants=auth-rpcgss-module.service -+After=rpc-gssd.service gssproxy.service rpc-svcgssd.service -+ - Wants=nfs-config.service - After=nfs-config.service - -diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service -index 6b13b32..941afe5 100644 ---- a/systemd/rpc-statd-notify.service -+++ b/systemd/rpc-statd-notify.service -@@ -14,6 +14,5 @@ After=nfs-config.service - - [Service] - EnvironmentFile=-/run/sysconfig/nfs-utils --Type=oneshot --RemainAfterExit=yes --ExecStart=-/usr/sbin/sm-notify -d $SMNOTIFYARGS -+Type=forking -+ExecStart=-/usr/sbin/sm-notify $SMNOTIFYARGS -diff --git a/tests/Makefile.am b/tests/Makefile.am -index faa8197..1f96264 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -11,3 +11,4 @@ SUBDIRS = nsm_client - MAINTAINERCLEANFILES = Makefile.in - - TESTS = t0001-statd-basic-mon-unmon.sh -+EXTRA_DIST = test-lib.sh $(TESTS) -diff --git a/tests/nsm_client/Makefile.am b/tests/nsm_client/Makefile.am -index 4c15346..a8fc131 100644 ---- a/tests/nsm_client/Makefile.am -+++ b/tests/nsm_client/Makefile.am -@@ -7,6 +7,7 @@ GENFILES_H = nlm_sm_inter.h - - GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) - -+EXTRA_DIST = nlm_sm_inter.x - - check_PROGRAMS = nsm_client - nsm_client_SOURCES = $(GENFILES) nsm_client.c -diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man -index 0de31b7..bee3f86 100644 ---- a/tools/mountstats/mountstats.man -+++ b/tools/mountstats/mountstats.man -@@ -1,32 +1,146 @@ - .\" - .\" mountstats(8) - .\" --.TH mountstats 8 "15 Apr 2010" -+.TH mountstats 8 "12 Dec 2014" - .SH NAME --mountstats \- Displays NFS client per-mount statistics -+mountstats \- Displays various NFS client per-mount statistics - .SH SYNOPSIS --.BI "mountstats [" "] " " [ " "]" --.SH DESCRIPTION --The - .B mountstats --command displays NFS client statisitics on each given --.I -+.RB [ \-h | \-\-help ] -+.RB [ \-v | \-\-version ] -+.RB [ \-f | \-\-file -+.IR infile ] -+.RB [ \-s | \-\-since -+.IR sincefile ] -+.\" .RB [ \-n | \-\-nfs | \-r | \-\-rpc | \-R | \-\-raw ] -+.R [ -+.RB [ \-n | \-\-nfs ] -+.R | -+.RB [ \-r | \-\-rpc ] -+.R | -+.RB [ \-R | \-\-raw ] -+.R ] -+.RI [ mountpoint ] ... -+.P -+.B mountstats iostat -+.RB [ \-h | \-\-help ] -+.RB [ \-v | \-\-version ] -+.RB [ \-f | \-\-file -+.IR infile ] -+.RB [ \-s | \-\-since -+.IR sincefile ] -+.RI [ interval ] -+.RI [ count ] -+.RI [ mountpoint ] ... -+.P -+.B mounstats nfsstat -+.RB [ \-h | \-\-help ] -+.RB [ \-v | \-\-version ] -+.RB [ \-f | \-\-file -+.IR infile ] -+.RB [ \-s | \-\-since -+.IR sincefile ] -+.RB [ \-3 ] -+.RB [ \-4 ] -+.RI [ mountpoint ] ... -+.P -+.SH DESCRIPTION -+.RB "The " mountstats " command displays various NFS client statisitics for each given" -+.IR mountpoint . -+.P -+.RI "If no " mountpoint " is given, statistics will be displayed for all NFS mountpoints on the client." -+.SS Sub-commands -+Valid -+.BR mountstats (8) -+subcommands are: -+.IP "\fBmountstats\fP" -+Display a combination of per-op RPC statistics, NFS event counts, and NFS byte counts. This is the default sub-command that will be executed if no sub-command is given. -+.IP "\fBiostat\fP" -+Display iostat-like statistics. -+.IP "\fBnfsstat\fP" -+Display nfsstat-like statistics. - .SH OPTIONS -+.SS Options valid for all sub-commands -+.TP -+.B \-h, \-\-help -+show the help message and exit -+.TP -+.B \-v, \-\-version -+show program's version number and exit -+.TP -+\fB\-f \fIinfile\fR, \fB\-\-file \fIinfile -+Read stats from -+.I infile -+instead of -+.IR /proc/self/mountstats ". " infile -+must be in the same format as -+.IR /proc/self/mountstats . -+This may be used with the -+.BR \-S | \-\-since -+options to display the delta between two different points in time. -+This may not be used with the -+.IR interval " or " count -+options of the -+.B iostat -+sub-command. - .TP --.B " \-\-nfs --display only the NFS statistics -+\fB\-S \fIsincefile\fR, \fB\-\-since \fIsincefile -+Show difference between current stats and those in -+.IR sincefile ". " sincefile -+must be in the same format as -+.IR /proc/self/mountstats . -+This may be used with the -+.BR \-f | \-\-file -+options to display the delta between two different points in time. -+This may not be used with the -+.IR interval " or " count -+options of the -+.B iostat -+sub-command. -+.SS Options specific to the mountstats sub-command -+.B \-n, \-\-nfs -+Display only the NFS statistics - .TP --.B " \-\-rpc --display only the RPC statistics -+.B \-r, \-\-rpc -+Display only the RPC statistics - .TP --.B " \-\-version --display the version of this command -+.B \-R, \-\-raw -+Display only the raw statistics. This is intended for use with the -+.BR \-f | \-\-file -+and -+.BR \-S | \-\-since -+options. -+.SS Options specific to the iostat sub-command -+.IP "\fIinterval\fP" -+Specifies the amount of time in seconds between each report. The first report contains statistics for the time since each file system was mounted. Each subsequent report contains statistics collected during the interval since the previous report. This may not be used with the -+.BR \-f | \-\-file -+or -+.BR \-s | \-\-since -+options. -+.P -+.IP "\fIcount\fP" -+Determines the number of reports generated at -+.I interval -+seconds apart. If the -+.I interval -+parameter is specified without the -+.I count -+parameter, the command generates reports continuously. This may not be used with the -+.BR \-f | \-\-file -+or -+.BR \-s | \-\-since -+options. -+.SS Options specific to the nfsstat sub-command -+.IP "\fB\-3\fP" -+Show only NFS version 3 statistics. The default is to show both version 3 and version 4 statistics. -+.IP "\fB\-4\fP" -+Show only NFS version 4 statistics. The default is to show both version 3 and version 4 statistics. - .SH FILES - .TP - .B /proc/self/mountstats - .SH SEE ALSO - .BR iostat (8), - .BR nfsiostat (8), --.BR nfsstat(8) -+.BR nfsstat (8) - .SH AUTHOR - Chuck Lever -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index 1fb3e2f..fd73feb 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -24,14 +24,189 @@ MA 02110-1301 USA - """ - - import sys, os, time -+from operator import itemgetter, add -+try: -+ import argparse -+except ImportError: -+ print('%s: Failed to import argparse - make sure argparse is installed!' -+ % sys.argv[0]) -+ sys.exit(1) - --Mountstats_version = '0.2' -+Mountstats_version = '0.3' - - def difference(x, y): - """Used for a map() function - """ - return x - y - -+NfsEventCounters = [ -+ 'inoderevalidates', -+ 'dentryrevalidates', -+ 'datainvalidates', -+ 'attrinvalidates', -+ 'vfsopen', -+ 'vfslookup', -+ 'vfspermission', -+ 'vfsupdatepage', -+ 'vfsreadpage', -+ 'vfsreadpages', -+ 'vfswritepage', -+ 'vfswritepages', -+ 'vfsreaddir', -+ 'vfssetattr', -+ 'vfsflush', -+ 'vfsfsync', -+ 'vfslock', -+ 'vfsrelease', -+ 'congestionwait', -+ 'setattrtrunc', -+ 'extendwrite', -+ 'sillyrenames', -+ 'shortreads', -+ 'shortwrites', -+ 'delay', -+ 'pnfsreads', -+ 'pnfswrites' -+] -+ -+NfsByteCounters = [ -+ 'normalreadbytes', -+ 'normalwritebytes', -+ 'directreadbytes', -+ 'directwritebytes', -+ 'serverreadbytes', -+ 'serverwritebytes', -+ 'readpages', -+ 'writepages' -+] -+ -+XprtUdpCounters = [ -+ 'port', -+ 'bind_count', -+ 'rpcsends', -+ 'rpcreceives', -+ 'badxids', -+ 'inflightsends', -+ 'backlogutil' -+] -+ -+XprtTcpCounters = [ -+ 'port', -+ 'bind_count', -+ 'connect_count', -+ 'connect_time', -+ 'idle_time', -+ 'rpcsends', -+ 'rpcreceives', -+ 'badxids', -+ 'inflightsends', -+ 'backlogutil' -+] -+ -+XprtRdmaCounters = [ -+ 'port', -+ 'bind_count', -+ 'connect_count', -+ 'connect_time', -+ 'idle_time', -+ 'rpcsends', -+ 'rpcreceives', -+ 'badxids', -+ 'backlogutil', -+ 'read_chunks', -+ 'write_chunks', -+ 'reply_chunks', -+ 'total_rdma_req', -+ 'total_rdma_rep', -+ 'pullup', -+ 'fixup', -+ 'hardway', -+ 'failed_marshal', -+ 'bad_reply' -+] -+ -+Nfsv3ops = [ -+ 'NULL', -+ 'GETATTR', -+ 'SETATTR', -+ 'LOOKUP', -+ 'ACCESS', -+ 'READLINK', -+ 'READ', -+ 'WRITE', -+ 'CREATE', -+ 'MKDIR', -+ 'SYMLINK', -+ 'MKNOD', -+ 'REMOVE', -+ 'RMDIR', -+ 'RENAME', -+ 'LINK', -+ 'READDIR', -+ 'READDIRPLUS', -+ 'FSSTAT', -+ 'FSINFO', -+ 'PATHCONF', -+ 'COMMIT' -+] -+ -+Nfsv4ops = [ -+ 'NULL', -+ 'READ', -+ 'WRITE', -+ 'COMMIT', -+ 'OPEN', -+ 'OPEN_CONFIRM', -+ 'OPEN_NOATTR', -+ 'OPEN_DOWNGRADE', -+ 'CLOSE', -+ 'SETATTR', -+ 'FSINFO', -+ 'RENEW', -+ 'SETCLIENTID', -+ 'SETCLIENTID_CONFIRM', -+ 'LOCK', -+ 'LOCKT', -+ 'LOCKU', -+ 'ACCESS', -+ 'GETATTR', -+ 'LOOKUP', -+ 'LOOKUP_ROOT', -+ 'REMOVE', -+ 'RENAME', -+ 'LINK', -+ 'SYMLINK', -+ 'CREATE', -+ 'PATHCONF', -+ 'STATFS', -+ 'READLINK', -+ 'READDIR', -+ 'SERVER_CAPS', -+ 'DELEGRETURN', -+ 'GETACL', -+ 'SETACL', -+ 'FS_LOCATIONS', -+ 'RELEASE_LOCKOWNER', -+ 'SECINFO', -+ 'FSID_PRESENT', -+ 'EXCHANGE_ID', -+ 'CREATE_SESSION', -+ 'DESTROY_SESSION', -+ 'SEQUENCE', -+ 'GET_LEASE_TIME', -+ 'RECLAIM_COMPLETE', -+ 'LAYOUTGET', -+ 'GETDEVICEINFO', -+ 'LAYOUTCOMMIT', -+ 'LAYOUTRETURN', -+ 'SECINFO_NO_NAME', -+ 'TEST_STATEID', -+ 'FREE_STATEID', -+ 'GETDEVICELIST', -+ 'BIND_CONN_TO_SESSION', -+ 'DESTROY_CLIENTID' -+] -+ - class DeviceData: - """DeviceData objects provide methods for parsing and displaying - data for a single mount grabbed from /proc/self/mountstats -@@ -46,13 +221,13 @@ class DeviceData: - self.__nfs_data['export'] = words[1] - self.__nfs_data['mountpoint'] = words[4] - self.__nfs_data['fstype'] = words[7] -- if words[7].find('nfs') != -1: -+ if words[7].find('nfs') != -1 and words[7] != 'nfsd': - self.__nfs_data['statvers'] = words[8] - elif 'nfs' in words or 'nfs4' in words: - self.__nfs_data['export'] = words[0] - self.__nfs_data['mountpoint'] = words[3] - self.__nfs_data['fstype'] = words[6] -- if words[6].find('nfs') != -1: -+ if words[6].find('nfs') != -1 and words[6] != 'nfsd': - self.__nfs_data['statvers'] = words[7] - elif words[0] == 'age:': - self.__nfs_data['age'] = int(words[1]) -@@ -69,36 +244,18 @@ class DeviceData: - if self.__nfs_data['flavor'] == 6: - self.__nfs_data['pseudoflavor'] = int(keys[1].split('=')[1]) - elif words[0] == 'events:': -- self.__nfs_data['inoderevalidates'] = int(words[1]) -- self.__nfs_data['dentryrevalidates'] = int(words[2]) -- self.__nfs_data['datainvalidates'] = int(words[3]) -- self.__nfs_data['attrinvalidates'] = int(words[4]) -- self.__nfs_data['syncinodes'] = int(words[5]) -- self.__nfs_data['vfsopen'] = int(words[6]) -- self.__nfs_data['vfslookup'] = int(words[7]) -- self.__nfs_data['vfspermission'] = int(words[8]) -- self.__nfs_data['vfsreadpage'] = int(words[9]) -- self.__nfs_data['vfsreadpages'] = int(words[10]) -- self.__nfs_data['vfswritepage'] = int(words[11]) -- self.__nfs_data['vfswritepages'] = int(words[12]) -- self.__nfs_data['vfsreaddir'] = int(words[13]) -- self.__nfs_data['vfsflush'] = int(words[14]) -- self.__nfs_data['vfsfsync'] = int(words[15]) -- self.__nfs_data['vfslock'] = int(words[16]) -- self.__nfs_data['vfsrelease'] = int(words[17]) -- self.__nfs_data['setattrtrunc'] = int(words[18]) -- self.__nfs_data['extendwrite'] = int(words[19]) -- self.__nfs_data['sillyrenames'] = int(words[20]) -- self.__nfs_data['shortreads'] = int(words[21]) -- self.__nfs_data['shortwrites'] = int(words[22]) -- self.__nfs_data['delay'] = int(words[23]) -+ i = 1 -+ for key in NfsEventCounters: -+ try: -+ self.__nfs_data[key] = int(words[i]) -+ except IndexError as err: -+ self.__nfs_data[key] = 0 -+ i += 1 - elif words[0] == 'bytes:': -- self.__nfs_data['normalreadbytes'] = int(words[1]) -- self.__nfs_data['normalwritebytes'] = int(words[2]) -- self.__nfs_data['directreadbytes'] = int(words[3]) -- self.__nfs_data['directwritebytes'] = int(words[4]) -- self.__nfs_data['serverreadbytes'] = int(words[5]) -- self.__nfs_data['serverwritebytes'] = int(words[6]) -+ i = 1 -+ for key in NfsByteCounters: -+ self.__nfs_data[key] = int(words[i]) -+ i += 1 - - def __parse_rpc_line(self, words): - if words[0] == 'RPC': -@@ -107,44 +264,20 @@ class DeviceData: - elif words[0] == 'xprt:': - self.__rpc_data['protocol'] = words[1] - if words[1] == 'udp': -- self.__rpc_data['port'] = int(words[2]) -- self.__rpc_data['bind_count'] = int(words[3]) -- self.__rpc_data['rpcsends'] = int(words[4]) -- self.__rpc_data['rpcreceives'] = int(words[5]) -- self.__rpc_data['badxids'] = int(words[6]) -- self.__rpc_data['inflightsends'] = int(words[7]) -- self.__rpc_data['backlogutil'] = int(words[8]) -+ i = 2 -+ for key in XprtUdpCounters: -+ self.__rpc_data[key] = int(words[i]) -+ i += 1 - elif words[1] == 'tcp': -- self.__rpc_data['port'] = words[2] -- self.__rpc_data['bind_count'] = int(words[3]) -- self.__rpc_data['connect_count'] = int(words[4]) -- self.__rpc_data['connect_time'] = int(words[5]) -- self.__rpc_data['idle_time'] = int(words[6]) -- self.__rpc_data['rpcsends'] = int(words[7]) -- self.__rpc_data['rpcreceives'] = int(words[8]) -- self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['inflightsends'] = int(words[10]) -- self.__rpc_data['backlogutil'] = int(words[11]) -+ i = 2 -+ for key in XprtTcpCounters: -+ self.__rpc_data[key] = int(words[i]) -+ i += 1 - elif words[1] == 'rdma': -- self.__rpc_data['port'] = words[2] -- self.__rpc_data['bind_count'] = int(words[3]) -- self.__rpc_data['connect_count'] = int(words[4]) -- self.__rpc_data['connect_time'] = int(words[5]) -- self.__rpc_data['idle_time'] = int(words[6]) -- self.__rpc_data['rpcsends'] = int(words[7]) -- self.__rpc_data['rpcreceives'] = int(words[8]) -- self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['backlogutil'] = int(words[10]) -- self.__rpc_data['read_chunks'] = int(words[11]) -- self.__rpc_data['write_chunks'] = int(words[12]) -- self.__rpc_data['reply_chunks'] = int(words[13]) -- self.__rpc_data['total_rdma_req'] = int(words[14]) -- self.__rpc_data['total_rdma_rep'] = int(words[15]) -- self.__rpc_data['pullup'] = int(words[16]) -- self.__rpc_data['fixup'] = int(words[17]) -- self.__rpc_data['hardway'] = int(words[18]) -- self.__rpc_data['failed_marshal'] = int(words[19]) -- self.__rpc_data['bad_reply'] = int(words[20]) -+ i = 2 -+ for key in XprtRdmaCounters: -+ self.__rpc_data[key] = int(words[i]) -+ i += 1 - elif words[0] == 'per-op': - self.__rpc_data['per-op'] = words - else: -@@ -178,12 +311,55 @@ class DeviceData: - return True - return False - -- def display_nfs_options(self): -- """Pretty-print the NFS options -+ def nfs_version(self): -+ if self.is_nfs_mountpoint(): -+ prog, vers = self.__rpc_data['programversion'].split('/') -+ return int(vers) -+ -+ def display_raw_stats(self): -+ """Prints out stats in the same format as /proc/self/mountstats - """ -+ print('device %s mounted on %s with fstype %s %s' % \ -+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'], \ -+ self.__nfs_data['fstype'], self.__nfs_data['statvers'])) -+ print('\topts:\t%s' % ','.join(self.__nfs_data['mountoptions'])) -+ print('\tage:\t%d' % self.__nfs_data['age']) -+ print('\tcaps:\t%s' % ','.join(self.__nfs_data['servercapabilities'])) -+ print('\tsec:\tflavor=%d,pseudoflavor=%d' % (self.__nfs_data['flavor'], \ -+ self.__nfs_data['pseudoflavor'])) -+ print('\tevents:\t%s' % " ".join([str(self.__nfs_data[key]) for key in NfsEventCounters])) -+ print('\tbytes:\t%s' % " ".join([str(self.__nfs_data[key]) for key in NfsByteCounters])) -+ print('\tRPC iostats version: %1.1f p/v: %s (nfs)' % (self.__rpc_data['statsvers'], \ -+ self.__rpc_data['programversion'])) -+ if self.__rpc_data['protocol'] == 'udp': -+ print('\txprt:\tudp %s' % " ".join([str(self.__rpc_data[key]) for key in XprtUdpCounters])) -+ elif self.__rpc_data['protocol'] == 'tcp': -+ print('\txprt:\ttcp %s' % " ".join([str(self.__rpc_data[key]) for key in XprtTcpCounters])) -+ elif self.__rpc_data['protocol'] == 'rdma': -+ print('\txprt:\trdma %s' % " ".join([str(self.__rpc_data[key]) for key in XprtRdmaCounters])) -+ else: -+ raise Exception('Unknown RPC transport protocol %s' % self.__rpc_data['protocol']) -+ print('\tper-op statistics') -+ prog, vers = self.__rpc_data['programversion'].split('/') -+ if vers == '3': -+ for op in Nfsv3ops: -+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ elif vers == '4': -+ for op in Nfsv4ops: -+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op]))) -+ else: -+ print('\tnot implemented for version %d' % vers) -+ print() -+ -+ def display_stats_header(self): - print('Stats for %s mounted on %s:' % \ - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) - -+ def display_nfs_options(self): -+ """Pretty-print the NFS options -+ """ -+ self.display_stats_header() -+ - print(' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])) - print(' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])) - if 'nfsv4flags' in self.__nfs_data: -@@ -201,7 +377,6 @@ class DeviceData: - print('Cache events:') - print(' data cache invalidated %d times' % self.__nfs_data['datainvalidates']) - print(' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']) -- print(' inodes synced %d times' % self.__nfs_data['syncinodes']) - print() - print('VFS calls:') - print(' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']) -@@ -262,29 +437,82 @@ class DeviceData: - """ - sends = self.__rpc_data['rpcsends'] - -- # XXX: these should be sorted by 'count' -- print() -+ allstats = [] - for op in self.__rpc_data['ops']: -- stats = self.__rpc_data[op] -- count = stats[0] -- retrans = stats[1] - count -+ allstats.append([op] + self.__rpc_data[op]) -+ -+ print() -+ for stats in sorted(allstats, key=itemgetter(1), reverse=True): -+ count = stats[1] - if count != 0: -- print('%s:' % op) -+ print('%s:' % stats[0]) - print('\t%d ops (%d%%)' % \ - (count, ((count * 100) / sends)), end=' ') -- print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') -- print('\t%d major timeouts' % stats[2]) -+ retrans = stats[2] - count -+ if retrans != 0: -+ print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') -+ print('\t%d major timeouts' % stats[3]) -+ else: -+ print('') - print('\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ -- (stats[3] / count, stats[4] / count)) -- print('\tbacklog wait: %f' % (float(stats[5]) / count), end=' ') -- print('\tRTT: %f' % (float(stats[6]) / count), end=' ') -+ (stats[4] / count, stats[5] / count)) -+ print('\tbacklog wait: %f' % (float(stats[6]) / count), end=' ') -+ print('\tRTT: %f' % (float(stats[7]) / count), end=' ') - print('\ttotal execute time: %f (milliseconds)' % \ -- (float(stats[7]) / count)) -+ (float(stats[8]) / count)) -+ -+ def client_rpc_stats(self): -+ """Tally high-level rpc stats for the nfsstat command -+ """ -+ sends = 0 -+ trans = 0 -+ authrefrsh = 0 -+ for op in self.__rpc_data['ops']: -+ sends += self.__rpc_data[op][0] -+ trans += self.__rpc_data[op][1] -+ retrans = trans - sends -+ # authrefresh stats don't actually get captured in -+ # /proc/self/mountstats, so we fudge it here -+ authrefrsh = sends -+ return (sends, trans, authrefrsh) -+ -+ def display_nfsstat_stats(self): -+ """Pretty-print nfsstat-style stats -+ """ -+ sends = 0 -+ for op in self.__rpc_data['ops']: -+ sends += self.__rpc_data[op][0] -+ if sends == 0: -+ return -+ print() -+ vers = self.nfs_version() -+ print('Client nfs v%d' % vers) -+ info = [] -+ for op in self.__rpc_data['ops']: -+ print('%-13s' % str.lower(op)[:12], end='') -+ count = self.__rpc_data[op][0] -+ pct = (count * 100) / sends -+ info.append((count, pct)) -+ if (self.__rpc_data['ops'].index(op) + 1) % 6 == 0: -+ print() -+ for (count, pct) in info: -+ print('%-8u%3u%% ' % (count, pct), end='') -+ print() -+ info = [] -+ print() -+ if len(info) > 0: -+ for (count, pct) in info: -+ print('%-8u%3u%% ' % (count, pct), end='') -+ print() - - def compare_iostats(self, old_stats): - """Return the difference between two sets of stats - """ -+ if old_stats.__nfs_data['age'] > self.__nfs_data['age']: -+ return self -+ - result = DeviceData() -+ protocol = self.__rpc_data['protocol'] - - # copy self into result - for key, value in self.__nfs_data.items(): -@@ -299,70 +527,118 @@ class DeviceData: - for op in result.__rpc_data['ops']: - result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) - -- # update the remaining keys we care about -- result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -- result.__rpc_data['backlogutil'] -= old_stats.__rpc_data['backlogutil'] -- result.__nfs_data['serverreadbytes'] -= old_stats.__nfs_data['serverreadbytes'] -- result.__nfs_data['serverwritebytes'] -= old_stats.__nfs_data['serverwritebytes'] -- -+ # update the remaining keys -+ if protocol == 'udp': -+ for key in XprtUdpCounters: -+ result.__rpc_data[key] -= old_stats.__rpc_data[key] -+ elif protocol == 'tcp': -+ for key in XprtTcpCounters: -+ result.__rpc_data[key] -= old_stats.__rpc_data[key] -+ elif protocol == 'rdma': -+ for key in XprtRdmaCounters: -+ result.__rpc_data[key] -= old_stats.__rpc_data[key] -+ result.__nfs_data['age'] -= old_stats.__nfs_data['age'] -+ for key in NfsEventCounters: -+ result.__nfs_data[key] -= old_stats.__nfs_data[key] -+ for key in NfsByteCounters: -+ result.__nfs_data[key] -= old_stats.__nfs_data[key] - return result - -+ def setup_accumulator(self, ops): -+ """Initialize a DeviceData instance to tally stats for all mountpoints -+ with the same major version. This is for the nfsstat command. -+ """ -+ if ops == Nfsv3ops: -+ self.__rpc_data['programversion'] = '100003/3' -+ self.__nfs_data['fstype'] = 'nfs' -+ elif ops == Nfsv4ops: -+ self.__rpc_data['programversion'] = '100003/4' -+ self.__nfs_data['fstype'] = 'nfs4' -+ self.__rpc_data['ops'] = ops -+ for op in ops: -+ self.__rpc_data[op] = [0 for i in range(8)] -+ -+ def accumulate_iostats(self, new_stats): -+ """Accumulate counters from all RPC op buckets in new_stats. This is -+ 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])) -+ -+ def __print_rpc_op_stats(self, op, sample_time): -+ """Print generic stats for one RPC op -+ """ -+ if op not in self.__rpc_data: -+ return -+ -+ rpc_stats = self.__rpc_data[op] -+ ops = float(rpc_stats[0]) -+ retrans = float(rpc_stats[1] - rpc_stats[0]) -+ kilobytes = float(rpc_stats[3] + rpc_stats[4]) / 1024 -+ rtt = float(rpc_stats[6]) -+ exe = float(rpc_stats[7]) -+ -+ # prevent floating point exceptions -+ if ops != 0: -+ kb_per_op = kilobytes / ops -+ retrans_percent = (retrans * 100) / ops -+ rtt_per_op = rtt / ops -+ exe_per_op = exe / ops -+ else: -+ kb_per_op = 0.0 -+ retrans_percent = 0.0 -+ rtt_per_op = 0.0 -+ exe_per_op = 0.0 -+ -+ op += ':' -+ print(format(op.lower(), '<16s'), end='') -+ print(format('ops/s', '>8s'), end='') -+ print(format('kB/s', '>16s'), end='') -+ print(format('kB/op', '>16s'), end='') -+ print(format('retrans', '>16s'), end='') -+ print(format('avg RTT (ms)', '>16s'), end='') -+ print(format('avg exe (ms)', '>16s')) -+ -+ print(format((ops / sample_time), '>24.3f'), end='') -+ print(format((kilobytes / sample_time), '>16.3f'), end='') -+ print(format(kb_per_op, '>16.3f'), end='') -+ retransmits = '{0:>10.0f} ({1:>3.1f}%)'.format(retrans, retrans_percent).strip() -+ print(format(retransmits, '>16'), end='') -+ print(format(rtt_per_op, '>16.3f'), end='') -+ print(format(exe_per_op, '>16.3f')) -+ - def display_iostats(self, sample_time): - """Display NFS and RPC stats in an iostat-like way - """ - sends = float(self.__rpc_data['rpcsends']) - if sample_time == 0: - sample_time = float(self.__nfs_data['age']) -+ # sample_time could still be zero if the export was just mounted. -+ # Set it to 1 to avoid divide by zero errors in this case since we'll -+ # likely still have relevant mount statistics to show. -+ # -+ if sample_time == 0: -+ sample_time = 1; -+ if sends != 0: -+ backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time -+ else: -+ backlog = 0.0 - - print() - print('%s mounted on %s:' % \ - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) -+ print() - -- print('\top/s\trpc bklog') -- print('\t%.2f' % (sends / sample_time), end=' ') -- if sends != 0: -- print('\t%.2f' % \ -- ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)) -- else: -- print('\t0.00') -- -- # reads: ops/s, kB/s, avg rtt, and avg exe -- # XXX: include avg xfer size and retransmits? -- read_rpc_stats = self.__rpc_data['READ'] -- ops = float(read_rpc_stats[0]) -- kilobytes = float(self.__nfs_data['serverreadbytes']) / 1024 -- rtt = float(read_rpc_stats[6]) -- exe = float(read_rpc_stats[7]) -- -- print('\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -- print('\t\t%.2f' % (ops / sample_time), end=' ') -- print('\t\t%.2f' % (kilobytes / sample_time), end=' ') -- if ops != 0: -- print('\t\t%.2f' % (rtt / ops), end=' ') -- print('\t\t%.2f' % (exe / ops)) -- else: -- print('\t\t0.00', end=' ') -- print('\t\t0.00') -- -- # writes: ops/s, kB/s, avg rtt, and avg exe -- # XXX: include avg xfer size and retransmits? -- write_rpc_stats = self.__rpc_data['WRITE'] -- ops = float(write_rpc_stats[0]) -- kilobytes = float(self.__nfs_data['serverwritebytes']) / 1024 -- rtt = float(write_rpc_stats[6]) -- exe = float(write_rpc_stats[7]) -- -- print('\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -- print('\t\t%.2f' % (ops / sample_time), end=' ') -- print('\t\t%.2f' % (kilobytes / sample_time), end=' ') -- if ops != 0: -- print('\t\t%.2f' % (rtt / ops), end=' ') -- print('\t\t%.2f' % (exe / ops)) -- else: -- print('\t\t0.00', end=' ') -- print('\t\t0.00') -+ print(format('ops/s', '>16') + format('rpc bklog', '>16')) -+ print(format((sends / sample_time), '>16.3f'), end='') -+ print(format(backlog, '>16.3f')) -+ print() - --def parse_stats_file(filename): -+ self.__print_rpc_op_stats('READ', sample_time) -+ self.__print_rpc_op_stats('WRITE', sample_time) -+ sys.stdout.flush() -+ -+def parse_stats_file(f): - """pop the contents of a mountstats file into a dictionary, - keyed by mount point. each value object is a list of the - lines in the mountstats file corresponding to the mount -@@ -371,7 +647,7 @@ def parse_stats_file(filename): - ms_dict = dict() - key = '' - -- f = open(filename) -+ f.seek(0) - for line in f.readlines(): - words = line.split() - if len(words) == 0: -@@ -385,132 +661,154 @@ def parse_stats_file(filename): - else: - new += [ line.strip() ] - ms_dict[key] = new -- f.close - - return ms_dict - --def print_mountstats_help(name): -- print('usage: %s [ options ] ' % name) -- print() -- print(' Version %s' % Mountstats_version) -- print() -- print(' Display NFS client per-mount statistics.') -- print() -- print(' --version display the version of this command') -- print(' --nfs display only the NFS statistics') -- print(' --rpc display only the RPC statistics') -- print(' --start sample and save statistics') -- print(' --end resample statistics and compare them with saved') -+def print_mountstats(stats, nfs_only, rpc_only, raw): -+ if nfs_only: -+ stats.display_nfs_options() -+ stats.display_nfs_events() -+ stats.display_nfs_bytes() -+ elif rpc_only: -+ stats.display_stats_header() -+ stats.display_rpc_generic_stats() -+ stats.display_rpc_op_stats() -+ elif raw: -+ stats.display_raw_stats() -+ else: -+ stats.display_nfs_options() -+ stats.display_nfs_bytes() -+ stats.display_rpc_generic_stats() -+ stats.display_rpc_op_stats() - print() - --def mountstats_command(): -+def mountstats_command(args): - """Mountstats command - """ -- mountpoints = [] -- nfs_only = False -- rpc_only = False -- -- for arg in sys.argv: -- if arg in ['-h', '--help', 'help', 'usage']: -- print_mountstats_help(prog) -- return -- -- if arg in ['-v', '--version', 'version']: -- print('%s version %s' % (sys.argv[0], Mountstats_version)) -- sys.exit(0) -- -- if arg in ['-n', '--nfs']: -- nfs_only = True -- continue -- -- if arg in ['-r', '--rpc']: -- rpc_only = True -- continue -+ mountstats = parse_stats_file(args.infile) -+ mountpoints = args.mountpoints - -- if arg in ['-s', '--start']: -- raise Exception('Sampling is not yet implemented') -+ # make certain devices contains only NFS mount points -+ if len(mountpoints) > 0: -+ check = [] -+ for device in mountpoints: -+ stats = DeviceData() -+ try: -+ stats.parse_stats(mountstats[device]) -+ if stats.is_nfs_mountpoint(): -+ check += [device] -+ except KeyError: -+ continue -+ mountpoints = check -+ else: -+ for device, descr in mountstats.items(): -+ stats = DeviceData() -+ stats.parse_stats(descr) -+ if stats.is_nfs_mountpoint(): -+ mountpoints += [device] -+ if len(mountpoints) == 0: -+ print('No NFS mount points were found') -+ return - -- if arg in ['-e', '--end']: -- raise Exception('Sampling is not yet implemented') -+ if args.since: -+ old_mountstats = parse_stats_file(args.since) - -- if arg == sys.argv[0]: -- continue -+ for mp in mountpoints: -+ stats = DeviceData() -+ stats.parse_stats(mountstats[mp]) -+ if not args.since: -+ print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw) -+ elif args.since and mp not in old_mountstats: -+ print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw) -+ else: -+ old_stats = DeviceData() -+ old_stats.parse_stats(old_mountstats[mp]) -+ diff_stats = stats.compare_iostats(old_stats) -+ print_mountstats(diff_stats, args.nfs_only, args.rpc_only, args.raw) - -- mountpoints += [arg] -+ args.infile.close() -+ if args.since: -+ args.since.close() - -- if mountpoints == []: -- print_mountstats_help(prog) -- return -+def nfsstat_command(args): -+ """nfsstat-like command for NFS mount points -+ """ -+ mountstats = parse_stats_file(args.infile) -+ mountpoints = args.mountpoints -+ v3stats = DeviceData() -+ v3stats.setup_accumulator(Nfsv3ops) -+ v4stats = DeviceData() -+ v4stats.setup_accumulator(Nfsv4ops) -+ -+ # ensure stats get printed if neither v3 nor v4 was specified -+ if args.show_v3 or args.show_v4: -+ show_both = False -+ else: -+ show_both = True - -- if rpc_only == True and nfs_only == True: -- print_mountstats_help(prog) -+ # make certain devices contains only NFS mount points -+ if len(mountpoints) > 0: -+ check = [] -+ for device in mountpoints: -+ stats = DeviceData() -+ try: -+ stats.parse_stats(mountstats[device]) -+ if stats.is_nfs_mountpoint(): -+ check += [device] -+ except KeyError: -+ continue -+ mountpoints = check -+ else: -+ for device, descr in mountstats.items(): -+ stats = DeviceData() -+ stats.parse_stats(descr) -+ if stats.is_nfs_mountpoint(): -+ mountpoints += [device] -+ if len(mountpoints) == 0: -+ print('No NFS mount points were found') - return - -- mountstats = parse_stats_file('/proc/self/mountstats') -+ if args.since: -+ old_mountstats = parse_stats_file(args.since) - - for mp in mountpoints: -- if mp not in mountstats: -- print('Statistics for mount point %s not found' % mp) -- continue -- - stats = DeviceData() - stats.parse_stats(mountstats[mp]) -+ vers = stats.nfs_version() - -- if not stats.is_nfs_mountpoint(): -- print('Mount point %s exists but is not an NFS mount' % mp) -- continue -- -- if nfs_only: -- stats.display_nfs_options() -- stats.display_nfs_events() -- stats.display_nfs_bytes() -- elif rpc_only: -- stats.display_rpc_generic_stats() -- stats.display_rpc_op_stats() -+ if not args.since: -+ acc_stats = stats -+ elif args.since and mp not in old_mountstats: -+ acc_stats = stats - else: -- stats.display_nfs_options() -- stats.display_nfs_bytes() -- stats.display_rpc_generic_stats() -- stats.display_rpc_op_stats() -+ old_stats = DeviceData() -+ old_stats.parse_stats(old_mountstats[mp]) -+ acc_stats = stats.compare_iostats(old_stats) - --def print_nfsstat_help(name): -- print('usage: %s [ options ]' % name) -- print() -- print(' Version %s' % Mountstats_version) -- print() -- print(' nfsstat-like program that uses NFS client per-mount statistics.') -- print() -+ if vers == 3 and (show_both or args.show_v3): -+ v3stats.accumulate_iostats(acc_stats) -+ elif vers == 4 and (show_both or args.show_v4): -+ v4stats.accumulate_iostats(acc_stats) - --def nfsstat_command(): -- print_nfsstat_help(prog) -+ sends, retrans, authrefrsh = map(add, v3stats.client_rpc_stats(), v4stats.client_rpc_stats()) -+ print('Client rpc stats:') -+ print('calls retrans authrefrsh') -+ print('%-11u%-11u%-11u' % (sends, retrans, authrefrsh)) - --def print_iostat_help(name): -- print('usage: %s [ [ ] ] [ ] ' % name) -- print() -- print(' Version %s' % Mountstats_version) -- print() -- print(' iostat-like program to display NFS client per-mount statistics.') -- print() -- print(' The parameter specifies the amount of time in seconds between') -- print(' each report. The first report contains statistics for the time since each') -- print(' file system was mounted. Each subsequent report contains statistics') -- print(' collected during the interval since the previous report.') -- print() -- print(' If the parameter is specified, the value of determines the') -- print(' number of reports generated at seconds apart. If the interval') -- print(' parameter is specified without the parameter, the command generates') -- print(' reports continuously.') -- print() -- print(' If one or more names are specified, statistics for only these') -- print(' mount points will be displayed. Otherwise, all NFS mount points on the') -- print(' client are listed.') -- print() -+ if show_both or args.show_v3: -+ v3stats.display_nfsstat_stats() -+ if show_both or args.show_v4: -+ v4stats.display_nfsstat_stats() -+ -+ args.infile.close() -+ if args.since: -+ args.since.close() - - def print_iostat_summary(old, new, devices, time): - for device in devices: - stats = DeviceData() - stats.parse_stats(new[device]) -- if not old: -+ if not old or device not in old: - stats.display_iostats(time) - else: - old_stats = DeviceData() -@@ -518,51 +816,28 @@ def print_iostat_summary(old, new, devices, time): - diff_stats = stats.compare_iostats(old_stats) - diff_stats.display_iostats(time) - --def iostat_command(): -+def iostat_command(args): - """iostat-like command for NFS mount points - """ -- mountstats = parse_stats_file('/proc/self/mountstats') -- devices = [] -- interval_seen = False -- count_seen = False -- -- for arg in sys.argv: -- if arg in ['-h', '--help', 'help', 'usage']: -- print_iostat_help(prog) -- return -- -- if arg in ['-v', '--version', 'version']: -- print('%s version %s' % (sys.argv[0], Mountstats_version)) -- return -- -- if arg == sys.argv[0]: -- continue -+ mountstats = parse_stats_file(args.infile) -+ devices = args.mountpoints - -- if arg in mountstats: -- devices += [arg] -- elif not interval_seen: -- interval = int(arg) -- if interval > 0: -- interval_seen = True -- else: -- print('Illegal value') -- return -- elif not count_seen: -- count = int(arg) -- if count > 0: -- count_seen = True -- else: -- print('Illegal value') -- return -+ if args.since: -+ old_mountstats = parse_stats_file(args.since) -+ else: -+ old_mountstats = None - - # make certain devices contains only NFS mount points - if len(devices) > 0: - check = [] - for device in devices: - stats = DeviceData() -- stats.parse_stats(mountstats[device]) -- if stats.is_nfs_mountpoint(): -- check += [device] -+ try: -+ stats.parse_stats(mountstats[device]) -+ if stats.is_nfs_mountpoint(): -+ check += [device] -+ except KeyError: -+ continue - devices = check - else: - for device, descr in mountstats.items(): -@@ -574,43 +849,145 @@ def iostat_command(): - print('No NFS mount points were found') - return - -- old_mountstats = None - sample_time = 0 - -- if not interval_seen: -+ if args.interval is None: - print_iostat_summary(old_mountstats, mountstats, devices, sample_time) - return - -- if count_seen: -+ if args.count is not None: -+ count = args.count - while count != 0: - print_iostat_summary(old_mountstats, mountstats, devices, sample_time) - old_mountstats = mountstats -- time.sleep(interval) -- sample_time = interval -- mountstats = parse_stats_file('/proc/self/mountstats') -+ time.sleep(args.interval) -+ sample_time = args.interval -+ mountstats = parse_stats_file(args.infile) - count -= 1 - else: - while True: - print_iostat_summary(old_mountstats, mountstats, devices, sample_time) - old_mountstats = mountstats -- time.sleep(interval) -- sample_time = interval -- mountstats = parse_stats_file('/proc/self/mountstats') -+ time.sleep(args.interval) -+ sample_time = args.interval -+ mountstats = parse_stats_file(args.infile) - --# --# Main --# --prog = os.path.basename(sys.argv[0]) -+ args.infile.close() -+ if args.since: -+ args.since.close() -+ -+class ICMAction(argparse.Action): -+ """Custom action to deal with interval, count, and mountpoints. -+ """ -+ def __call__(self, parser, namespace, values, option_string=None): -+ if namespace.mountpoints is None: -+ namespace.mountpoints = [] -+ if values is None: -+ return -+ elif (type(values) == type([])): -+ for value in values: -+ self._handle_one(namespace, value) -+ else: -+ self._handle_one(namespace, values) -+ -+ def _handle_one(self, namespace, value): -+ try: -+ intval = int(value) -+ if namespace.infile.name != '/proc/self/mountstats': -+ raise argparse.ArgumentError(self, "not allowed with argument -f/--file or -S/--since") -+ self._handle_int(namespace, intval) -+ except ValueError: -+ namespace.mountpoints.append(value) -+ -+ def _handle_int(self, namespace, value): -+ if namespace.interval is None: -+ namespace.interval = value -+ elif namespace.count is None: -+ namespace.count = value -+ else: -+ raise argparse.ArgumentError(self, "too many integer arguments") -+ -+def main(): -+ parser = argparse.ArgumentParser(epilog='For specific sub-command help, ' -+ 'run \'mountstats SUB-COMMAND -h|--help\'') -+ subparsers = parser.add_subparsers(help='sub-command help') -+ -+ common_parser = argparse.ArgumentParser(add_help=False) -+ common_parser.add_argument('-v', '--version', action='version', -+ version='mountstats ' + Mountstats_version) -+ common_parser.add_argument('-f', '--file', default=open('/proc/self/mountstats', 'r'), -+ type=argparse.FileType('r'), dest='infile', -+ help='Read stats from %(dest)s instead of /proc/self/mountstats') -+ common_parser.add_argument('-S', '--since', type=argparse.FileType('r'), -+ metavar='SINCEFILE', -+ help='Show difference between current stats and those in SINCEFILE') -+ -+ mountstats_parser = subparsers.add_parser('mountstats', -+ parents=[common_parser], -+ help='Display a combination of per-op RPC statistics, NFS event counts, and NFS byte counts. ' -+ 'This is the default sub-command if no sub-command is given.') -+ group = mountstats_parser.add_mutually_exclusive_group() -+ group.add_argument('-n', '--nfs', action='store_true', dest='nfs_only', -+ help='Display only the NFS statistics') -+ group.add_argument('-r', '--rpc', action='store_true', dest='rpc_only', -+ help='Display only the RPC statistics') -+ group.add_argument('-R', '--raw', action='store_true', -+ help='Display only the raw statistics') -+ # The mountpoints argument cannot be moved into the common_parser because -+ # it will screw up the parsing of the iostat arguments (interval and count) -+ mountstats_parser.add_argument('mountpoints', nargs='*', metavar='mountpoint', -+ help='Display statistics for this mountpoint. More than one may be specified. ' -+ 'If absent, statistics for all NFS mountpoints will be generated.') -+ mountstats_parser.set_defaults(func=mountstats_command) -+ -+ nfsstat_parser = subparsers.add_parser('nfsstat', -+ parents=[common_parser], -+ help='Display nfsstat-like statistics.') -+ nfsstat_parser.add_argument('-3', action='store_true', dest='show_v3', -+ help='Show NFS version 3 statistics') -+ nfsstat_parser.add_argument('-4', action='store_true', dest='show_v4', -+ help='Show NFS version 4 statistics') -+ # The mountpoints argument cannot be moved into the common_parser because -+ # it will screw up the parsing of the iostat arguments (interval and count) -+ nfsstat_parser.add_argument('mountpoints', nargs='*', metavar='mountpoint', -+ help='Display statistics for this mountpoint. More than one may be specified. ' -+ 'If absent, statistics for all NFS mountpoints will be generated.') -+ nfsstat_parser.set_defaults(func=nfsstat_command) -+ -+ iostat_parser = subparsers.add_parser('iostat', -+ parents=[common_parser], -+ help='Display iostat-like statistics.') -+ iostat_parser.add_argument('interval', nargs='?', action=ICMAction, -+ help='Number of seconds between reports. If absent, only one report will ' -+ 'be generated.') -+ iostat_parser.add_argument('count', nargs='?', action=ICMAction, -+ help='Number of reports generated at seconds apart. If absent, ' -+ 'reports will be generated continuously.') -+ # The mountpoints argument cannot be moved into the common_parser because -+ # it will screw up the parsing of the iostat arguments (interval and count) -+ iostat_parser.add_argument('mountpoints', nargs='*', action=ICMAction, metavar='mountpoint', -+ help='Display statsistics for this mountpoint. More than one may be specified. ' -+ 'If absent, statistics for all NFS mountpoints will be generated.') -+ iostat_parser.set_defaults(func=iostat_command) -+ -+ args = parser.parse_args() -+ return args.func(args) - - try: -- if prog == 'mountstats': -- mountstats_command() -- elif prog == 'ms-nfsstat': -- nfsstat_command() -- elif prog == 'ms-iostat': -- iostat_command() --except KeyboardInterrupt: -- print('Caught ^C... exiting') -+ if __name__ == '__main__': -+ # Run the mounstats sub-command if no sub-command (or the help flag) -+ # is given. If the argparse module ever gets support for optional -+ # (default) sub-commands, then this can be changed. -+ if len(sys.argv) == 1: -+ sys.argv.insert(1, 'mountstats') -+ elif sys.argv[1] not in ['-h', '--help', 'mountstats', 'iostat', 'nfsstat']: -+ sys.argv.insert(1, 'mountstats') -+ res = main() -+ sys.stdout.close() -+ sys.stderr.close() -+ sys.exit(res) -+except (SystemExit, KeyboardInterrupt, RuntimeError): - sys.exit(1) -+except IOError: -+ pass - --sys.exit(0) -diff --git a/tools/rpcgen/rpc_main.c b/tools/rpcgen/rpc_main.c -index 28aa60c..f81da47 100644 ---- a/tools/rpcgen/rpc_main.c -+++ b/tools/rpcgen/rpc_main.c -@@ -44,6 +44,7 @@ static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI"; - #include - #include - #include -+#include - #include "rpc_parse.h" - #include "rpc_util.h" - #include "rpc_scan.h" -@@ -389,7 +390,7 @@ c_output(char *infile, char *define, int extend, char *outfile) - open_output(infile, outfilename); - add_warning(); - if (infile && (include = extendfile(infile, ".h"))) { -- f_print(fout, "#include \"%s\"\n", include); -+ f_print(fout, "#include \"%s\"\n", basename(include)); - free(include); - /* .h file already contains rpc/rpc.h */ - } else -@@ -523,7 +524,7 @@ s_output(int argc, char **argv, char *infile, char *define, int extend, - open_output(infile, outfilename); - add_warning(); - if (infile && (include = extendfile(infile, ".h"))) { -- f_print(fout, "#include \"%s\"\n", include); -+ f_print(fout, "#include \"%s\"\n", basename(include)); - free(include); - } else - f_print(fout, "#include \n"); -@@ -630,7 +631,7 @@ l_output(char *infile, char *define, int extend, char *outfile) - if (Cflag) - f_print (fout, "#include /* for memset */\n"); - if (infile && (include = extendfile(infile, ".h"))) { -- f_print(fout, "#include \"%s\"\n", include); -+ f_print(fout, "#include \"%s\"\n", basename(include)); - free(include); - } else - f_print(fout, "#include \n"); -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index bdea12b..48eac00 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -47,7 +47,7 @@ static void error(nfs_export *exp, int err); - static void usage(const char *progname, int n); - static void validate_export(nfs_export *exp); - static int matchhostname(const char *hostname1, const char *hostname2); --static void export_d_read(const char *dname); -+static int export_d_read(const char *dname); - static void grab_lockfile(void); - static void release_lockfile(void); - -@@ -182,8 +182,11 @@ main(int argc, char **argv) - atexit(release_lockfile); - - if (f_export && ! f_ignore) { -- export_read(_PATH_EXPORTS); -- export_d_read(_PATH_EXPORTS_D); -+ if (! (export_read(_PATH_EXPORTS) + -+ export_d_read(_PATH_EXPORTS_D))) { -+ if (f_verbose) -+ xlog(L_WARNING, "No file systems exported!"); -+ } - } - if (f_export) { - if (f_all) -@@ -685,21 +688,22 @@ out: - - /* Based on mnt_table_parse_dir() in - util-linux-ng/shlibs/mount/src/tab_parse.c */ --static void -+static int - export_d_read(const char *dname) - { - int n = 0, i; - struct dirent **namelist = NULL; -+ int volumes = 0; - - - n = scandir(dname, &namelist, NULL, versionsort); - if (n < 0) { - if (errno == ENOENT) - /* Silently return */ -- return; -+ return volumes; - xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); - } else if (n == 0) -- return; -+ return volumes; - - for (i = 0; i < n; i++) { - struct dirent *d = namelist[i]; -@@ -729,14 +733,14 @@ export_d_read(const char *dname) - continue; - } - -- export_read(fname); -+ volumes += export_read(fname); - } - - for (i = 0; i < n; i++) - free(namelist[i]); - free(namelist); - -- return; -+ return volumes; - } - - static char -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index 9835117..62a70af 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -15,7 +15,6 @@ endif - sbin_PROGRAMS = $(sbin_PREFIXED) - - EXTRA_DIST = \ -- gss_destroy_creds \ - $(man8_MANS) - - COMMON_SRCS = \ -@@ -46,8 +45,8 @@ gssd_SOURCES = \ - write_bytes.h - - gssd_LDADD = ../../support/nfs/libnfs.a \ -- $(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS) --gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC) -+ $(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC) -+gssd_LDFLAGS = $(KRBLDFLAGS) - - gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS) -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 121feb1..1d8e6a7 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -78,6 +78,7 @@ - #include "nfsrpc.h" - #include "nfslib.h" - #include "gss_names.h" -+#include "misc.h" - - /* - * pollarray: -@@ -1250,7 +1251,7 @@ void - handle_gssd_upcall(struct clnt_info *clp) - { - uid_t uid; -- char *lbuf = NULL; -+ char lbuf[RPC_CHAN_BUF_SIZE]; - int lbuflen = 0; - char *p; - char *mech = NULL; -@@ -1260,11 +1261,14 @@ handle_gssd_upcall(struct clnt_info *clp) - - printerr(1, "handling gssd upcall (%s)\n", clp->dirname); - -- if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) { -+ lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf)); -+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { - printerr(0, "WARNING: handle_gssd_upcall: " - "failed reading request\n"); - return; - } -+ lbuf[lbuflen-1] = 0; -+ - printerr(2, "%s: '%s'\n", __func__, lbuf); - - /* find the mechanism name */ -@@ -1362,7 +1366,6 @@ handle_gssd_upcall(struct clnt_info *clp) - } - - out: -- free(lbuf); - free(mech); - free(enctypes); - free(target); -diff --git a/utils/gssd/svcgssd.h b/utils/gssd/svcgssd.h -index 9a2e2e8..02b5c7a 100644 ---- a/utils/gssd/svcgssd.h -+++ b/utils/gssd/svcgssd.h -@@ -35,7 +35,7 @@ - #include - #include - --void handle_nullreq(FILE *f); -+void handle_nullreq(int f); - void gssd_run(void); - - #define GSSD_SERVICE_NAME "nfs" -diff --git a/utils/gssd/svcgssd_main_loop.c b/utils/gssd/svcgssd_main_loop.c -index 2b4111c..b5681ce 100644 ---- a/utils/gssd/svcgssd_main_loop.c -+++ b/utils/gssd/svcgssd_main_loop.c -@@ -54,19 +54,18 @@ void - gssd_run() - { - int ret; -- FILE *f; -+ int f; - struct pollfd pollfd; - - #define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" - -- f = fopen(NULLRPC_FILE, "rw"); -- -- if (!f) { -+ f = open(NULLRPC_FILE, O_RDWR); -+ if (f < 0) { - printerr(0, "failed to open %s: %s\n", - NULLRPC_FILE, strerror(errno)); - exit(1); - } -- pollfd.fd = fileno(f); -+ pollfd.fd = f; - pollfd.events = POLLIN; - while (1) { - int save_err; -diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c -index 5bdb438..72ec254 100644 ---- a/utils/gssd/svcgssd_proc.c -+++ b/utils/gssd/svcgssd_proc.c -@@ -73,36 +73,35 @@ struct svc_cred { - int cr_ngroups; - gid_t cr_groups[NGROUPS]; - }; --static char vbuf[RPC_CHAN_BUF_SIZE]; - - static int - do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, - gss_OID mech, gss_buffer_desc *context_token, - int32_t endtime, char *client_name) - { -- FILE *f; -- int i; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int i, f, err, blen; - char *fname = NULL; -- int err; - - printerr(1, "doing downcall\n"); - if ((fname = mech2file(mech)) == NULL) - goto out_err; -- f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w"); -- if (f == NULL) { -+ -+ f = open(SVCGSSD_CONTEXT_CHANNEL, O_WRONLY); -+ if (f < 0) { - printerr(0, "WARNING: unable to open downcall channel " - "%s: %s\n", - SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); - goto out_err; - } -- setvbuf(f, vbuf, _IOLBF, RPC_CHAN_BUF_SIZE); -- qword_printhex(f, out_handle->value, out_handle->length); -+ bp = buf, blen = sizeof(buf); -+ qword_addhex(&bp, &blen, out_handle->value, out_handle->length); - /* XXX are types OK for the rest of this? */ - /* For context cache, use the actual context endtime */ -- qword_printint(f, endtime); -- qword_printint(f, cred->cr_uid); -- qword_printint(f, cred->cr_gid); -- qword_printint(f, cred->cr_ngroups); -+ qword_addint(&bp, &blen, endtime); -+ qword_addint(&bp, &blen, cred->cr_uid); -+ qword_addint(&bp, &blen, cred->cr_gid); -+ qword_addint(&bp, &blen, cred->cr_ngroups); - printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), " - "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n", - fname, out_handle->length, context_token->length, -@@ -110,19 +109,21 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, - client_name ? client_name : "", - cred->cr_uid, cred->cr_gid, cred->cr_ngroups); - for (i=0; i < cred->cr_ngroups; i++) { -- qword_printint(f, cred->cr_groups[i]); -+ qword_addint(&bp, &blen, cred->cr_groups[i]); - printerr(2, " (%4d) %d\n", i+1, cred->cr_groups[i]); - } -- qword_print(f, fname); -- qword_printhex(f, context_token->value, context_token->length); -+ qword_add(&bp, &blen, fname); -+ qword_addhex(&bp, &blen, context_token->value, context_token->length); - if (client_name) -- qword_print(f, client_name); -- err = qword_eol(f); -- if (err) { -+ qword_add(&bp, &blen, client_name); -+ qword_addeol(&bp, &blen); -+ err = 0; -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) { - printerr(1, "WARNING: error writing to downcall channel " - "%s: %s\n", SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); -+ err = -1; - } -- fclose(f); -+ close(f); - return err; - out_err: - printerr(1, "WARNING: downcall failed\n"); -@@ -317,7 +318,7 @@ print_hexl(const char *description, unsigned char *cp, int length) - #endif - - void --handle_nullreq(FILE *f) { -+handle_nullreq(int f) { - /* XXX initialize to a random integer to reduce chances of unnecessary - * invalidation of existing ctx's on restarting svcgssd. */ - static u_int32_t handle_seq = 0; -@@ -339,19 +340,21 @@ handle_nullreq(FILE *f) { - u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; - u_int32_t ignore_min_stat; - struct svc_cred cred; -- static char *lbuf = NULL; -- static int lbuflen = 0; -- static char *cp; -+ char lbuf[RPC_CHAN_BUF_SIZE]; -+ int lbuflen = 0; -+ char *cp; - int32_t ctx_endtime; - char *hostbased_name = NULL; - - printerr(1, "handling null request\n"); - -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) { -+ lbuflen = read(f, lbuf, sizeof(lbuf)); -+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { - printerr(0, "WARNING: handle_nullreq: " - "failed reading request\n"); - return; - } -+ lbuf[lbuflen-1] = 0; - - cp = lbuf; - -diff --git a/utils/gssd/write_bytes.h b/utils/gssd/write_bytes.h -index 4fc72cc..b3f342b 100644 ---- a/utils/gssd/write_bytes.h -+++ b/utils/gssd/write_bytes.h -@@ -32,6 +32,7 @@ - #define _WRITE_BYTES_H_ - - #include -+#include - #include - #include /* for ntohl */ - -diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am -index 58b33ec..c2f8ba1 100644 ---- a/utils/idmapd/Makefile.am -+++ b/utils/idmapd/Makefile.am -@@ -7,8 +7,7 @@ KPREFIX = @kprefix@ - sbin_PROGRAMS = idmapd - - EXTRA_DIST = \ -- $(man8_MANS) \ -- idmapd.conf -+ $(man8_MANS) - - idmapd_SOURCES = \ - idmapd.c \ -diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am -index 5810936..e24f3bd 100644 ---- a/utils/mount/Makefile.am -+++ b/utils/mount/Makefile.am -@@ -8,19 +8,21 @@ man8_MANS = mount.nfs.man umount.nfs.man - man5_MANS = nfs.man - - sbin_PROGRAMS = mount.nfs --EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS) -+EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS) - mount_common = error.c network.c token.c \ - parse_opt.c parse_dev.c \ - nfsmount.c nfs4mount.c stropts.c\ - mount_constants.h error.h network.h token.h \ - parse_opt.h parse_dev.h \ -- nfs4_mount.h nfs_mount4.h stropts.h version.h \ -- mount_config.h utils.c utils.h -+ nfs4_mount.h stropts.h version.h \ -+ mount_config.h utils.c utils.h \ -+ nfs_mount.h - - if MOUNT_CONFIG - mount_common += configfile.c - man5_MANS += nfsmount.conf.man --EXTRA_DIST += nfsmount.conf -+else -+EXTRA_DIST += nfsmount.conf.man - endif - - mount_nfs_LDADD = ../../support/nfs/libnfs.a \ -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index 6f85dc9..fa46d54 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -174,7 +174,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - { - int rc, c; - char *spec = NULL, *opts = NULL; -- int ret = EX_FAIL; -+ int ret = EX_FAIL, verbose = 0; - - static const struct option longopts[] = { - { "force", 0, 0, 'f' }, -@@ -201,6 +201,8 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - return EX_USAGE; - } - -+ verbose = mnt_context_is_verbose(cxt); -+ - if (optind < argc) - spec = argv[optind++]; - -@@ -228,6 +230,10 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - goto err; - } - -+ if (verbose) -+ printf(_("%s: %s mount point detected\n"), spec, -+ mnt_context_get_fstype(cxt)); -+ - opts = retrieve_mount_options(mnt_context_get_fs(cxt)); - - if (!mnt_context_is_lazy(cxt)) { -@@ -263,6 +269,12 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) - } - ret = EX_SUCCESS; - err: -+ if (verbose) { -+ if (ret == EX_SUCCESS) -+ printf(_("%s: umounted\n"), spec); -+ else -+ printf(_("%s: umount failed\n"), spec); -+ } - free(opts); - return ret; - } -diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am -index 7db968b..9e1ab5c 100644 ---- a/utils/mountd/Makefile.am -+++ b/utils/mountd/Makefile.am -@@ -7,6 +7,7 @@ RPCPREFIX = rpc. - KPREFIX = @kprefix@ - sbin_PROGRAMS = mountd - -+noinst_HEADERS = fsloc.h - mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \ - svc_run.c fsloc.c v4root.c mountd.h - mountd_LDADD = ../../support/export/libexport.a \ -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 663a52a..c23d384 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -61,15 +61,13 @@ enum nfsd_fsid { - * Record is terminated with newline. - * - */ --static int cache_export_ent(char *domain, struct exportent *exp, char *p); -+static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path); - - #define INITIAL_MANAGED_GROUPS 100 - --char *lbuf = NULL; --int lbuflen = 0; - extern int use_ipaddr; - --static void auth_unix_ip(FILE *f) -+static void auth_unix_ip(int f) - { - /* requests are - * class IP-ADDR -@@ -78,23 +76,26 @@ static void auth_unix_ip(FILE *f) - * - * "nfsd" IP-ADDR expiry domainname - */ -- char *cp; - char class[20]; - char ipaddr[INET6_ADDRSTRLEN + 1]; - char *client = NULL; - struct addrinfo *tmp = NULL; -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) -- return; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen; -+ -+ blen = read(f, buf, sizeof(buf)); -+ if (blen <= 0 || buf[blen-1] != '\n') return; -+ buf[blen-1] = 0; - -- xlog(D_CALL, "auth_unix_ip: inbuf '%s'", lbuf); -+ xlog(D_CALL, "auth_unix_ip: inbuf '%s'", buf); - -- cp = lbuf; -+ bp = buf; - -- if (qword_get(&cp, class, 20) <= 0 || -+ if (qword_get(&bp, class, 20) <= 0 || - strcmp(class, "nfsd") != 0) - return; - -- if (qword_get(&cp, ipaddr, sizeof(ipaddr) - 1) <= 0) -+ if (qword_get(&bp, ipaddr, sizeof(ipaddr) - 1) <= 0) - return; - - tmp = host_pton(ipaddr); -@@ -113,16 +114,20 @@ static void auth_unix_ip(FILE *f) - freeaddrinfo(ai); - } - } -- qword_print(f, "nfsd"); -- qword_print(f, ipaddr); -- qword_printtimefrom(f, DEFAULT_TTL); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, "nfsd"); -+ qword_add(&bp, &blen, ipaddr); -+ qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); - if (use_ipaddr) { - memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1); - ipaddr[0] = '$'; -- qword_print(f, ipaddr); -+ qword_add(&bp, &blen, ipaddr); - } else if (client) -- qword_print(f, *client?client:"DEFAULT"); -- qword_eol(f); -+ qword_add(&bp, &blen, *client?client:"DEFAULT"); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ xlog(L_ERROR, "auth_unix_ip: error writing reply"); -+ - xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); - - free(client); -@@ -130,7 +135,7 @@ static void auth_unix_ip(FILE *f) - - } - --static void auth_unix_gid(FILE *f) -+static void auth_unix_gid(int f) - { - /* Request are - * uid -@@ -144,7 +149,8 @@ static void auth_unix_gid(FILE *f) - gid_t *more_groups; - int ngroups; - int rv, i; -- char *cp; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen; - - if (groups_len == 0) { - groups = malloc(sizeof(gid_t) * INITIAL_MANAGED_GROUPS); -@@ -156,11 +162,12 @@ static void auth_unix_gid(FILE *f) - - ngroups = groups_len; - -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) -- return; -+ blen = read(f, buf, sizeof(buf)); -+ if (blen <= 0 || buf[blen-1] != '\n') return; -+ buf[blen-1] = 0; - -- cp = lbuf; -- if (qword_get_uint(&cp, &uid) != 0) -+ bp = buf; -+ if (qword_get_uint(&bp, &uid) != 0) - return; - - pw = getpwuid(uid); -@@ -180,15 +187,19 @@ static void auth_unix_gid(FILE *f) - } - } - } -- qword_printuint(f, uid); -- qword_printtimefrom(f, DEFAULT_TTL); -+ -+ bp = buf; blen = sizeof(buf); -+ qword_adduint(&bp, &blen, uid); -+ qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); - if (rv >= 0) { -- qword_printuint(f, ngroups); -+ qword_adduint(&bp, &blen, ngroups); - for (i=0; i 7) - goto out; /* unknown type */ -- if ((fsidlen = qword_get(&cp, fsid, 32)) <= 0) -+ if ((fsidlen = qword_get(&bp, fsid, 32)) <= 0) - goto out; - if (parse_fsid(fsidtype, fsidlen, fsid, &parsed)) - goto out; -@@ -796,12 +809,13 @@ static void nfsd_fh(FILE *f) - } - - if (found) -- if (cache_export_ent(dom, found, found_path) < 0) -+ if (cache_export_ent(buf, sizeof(buf), dom, found, found_path) < 0) - found = 0; - -- qword_print(f, dom); -- qword_printint(f, fsidtype); -- qword_printhex(f, fsid, fsidlen); -+ bp = buf; blen = sizeof(buf); -+ qword_add(&bp, &blen, dom); -+ qword_addint(&bp, &blen, fsidtype); -+ qword_addhex(&bp, &blen, fsid, fsidlen); - /* The fsid -> path lookup can be quite expensive as it - * potentially stats and reads lots of devices, and some of those - * might have spun-down. The Answer is not likely to -@@ -810,20 +824,21 @@ static void nfsd_fh(FILE *f) - * timeout. Maybe this should be configurable on the command - * line. - */ -- qword_printint(f, 0x7fffffff); -+ qword_addint(&bp, &blen, 0x7fffffff); - if (found) -- qword_print(f, found_path); -- qword_eol(f); -- out: -+ qword_add(&bp, &blen, found_path); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) -+ xlog(L_ERROR, "nfsd_fh: error writing reply"); -+out: - if (found_path) - free(found_path); - freeaddrinfo(ai); - free(dom); - xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL); -- return; - } - --static void write_fsloc(FILE *f, struct exportent *ep) -+static void write_fsloc(char **bp, int *blen, struct exportent *ep) - { - struct servers *servers; - -@@ -833,20 +848,20 @@ static void write_fsloc(FILE *f, struct exportent *ep) - servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); - if (!servers) - return; -- qword_print(f, "fsloc"); -- qword_printint(f, servers->h_num); -+ qword_add(bp, blen, "fsloc"); -+ qword_addint(bp, blen, servers->h_num); - if (servers->h_num >= 0) { - int i; - for (i=0; ih_num; i++) { -- qword_print(f, servers->h_mp[i]->h_host); -- qword_print(f, servers->h_mp[i]->h_path); -+ qword_add(bp, blen, servers->h_mp[i]->h_host); -+ qword_add(bp, blen, servers->h_mp[i]->h_path); - } - } -- qword_printint(f, servers->h_referral); -+ qword_addint(bp, blen, servers->h_referral); - release_replicas(servers); - } - --static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) -+static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_mask) - { - struct sec_entry *p; - -@@ -857,45 +872,52 @@ static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) - return; - } - fix_pseudoflavor_flags(ep); -- qword_print(f, "secinfo"); -- qword_printint(f, p - ep->e_secinfo); -+ qword_add(bp, blen, "secinfo"); -+ qword_addint(bp, blen, p - ep->e_secinfo); - for (p = ep->e_secinfo; p->flav; p++) { -- qword_printint(f, p->flav->fnum); -- qword_printint(f, p->flags & flag_mask); -+ qword_addint(bp, blen, p->flav->fnum); -+ qword_addint(bp, blen, p->flags & flag_mask); - } - - } - --static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exp) -+static int dump_to_cache(int f, char *buf, int buflen, char *domain, char *path, struct exportent *exp) - { -- qword_print(f, domain); -- qword_print(f, path); -+ char *bp = buf; -+ int blen = buflen; -+ time_t now = time(0); -+ -+ qword_add(&bp, &blen, domain); -+ qword_add(&bp, &blen, path); - if (exp) { - int different_fs = strcmp(path, exp->e_path) != 0; - int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; - -- qword_printtimefrom(f, exp->e_ttl); -- qword_printint(f, exp->e_flags & flag_mask); -- qword_printint(f, exp->e_anonuid); -- qword_printint(f, exp->e_anongid); -- qword_printint(f, exp->e_fsid); -- write_fsloc(f, exp); -- write_secinfo(f, exp, flag_mask); -- if (exp->e_uuid == NULL || different_fs) { -- char u[16]; -- if (uuid_by_path(path, 0, 16, u)) { -- qword_print(f, "uuid"); -- qword_printhex(f, u, 16); -- } -- } else { -- char u[16]; -- get_uuid(exp->e_uuid, 16, u); -- qword_print(f, "uuid"); -- qword_printhex(f, u, 16); -- } -+ qword_adduint(&bp, &blen, now + exp->e_ttl); -+ qword_addint(&bp, &blen, exp->e_flags & flag_mask); -+ qword_addint(&bp, &blen, exp->e_anonuid); -+ qword_addint(&bp, &blen, exp->e_anongid); -+ qword_addint(&bp, &blen, exp->e_fsid); -+ write_fsloc(&bp, &blen, exp); -+ write_secinfo(&bp, &blen, exp, flag_mask); -+ if (exp->e_uuid == NULL || different_fs) { -+ char u[16]; -+ if (uuid_by_path(path, 0, 16, u)) { -+ qword_add(&bp, &blen, "uuid"); -+ qword_addhex(&bp, &blen, u, 16); -+ } -+ } else { -+ char u[16]; -+ get_uuid(exp->e_uuid, 16, u); -+ qword_add(&bp, &blen, "uuid"); -+ qword_addhex(&bp, &blen, u, 16); -+ } - } else -- qword_printtimefrom(f, DEFAULT_TTL); -- return qword_eol(f); -+ qword_adduint(&bp, &blen, now + DEFAULT_TTL); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0) return -1; -+ if (write(f, buf, bp - buf) != bp - buf) return -1; -+ return 0; - } - - static nfs_export * -@@ -1245,27 +1267,27 @@ static struct exportent *lookup_junction(char *dom, const char *pathname, - return exp; - } - --static void lookup_nonexport(FILE *f, char *dom, char *path, -+static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, - struct addrinfo *ai) - { - struct exportent *eep; - - eep = lookup_junction(dom, path, ai); -- dump_to_cache(f, dom, path, eep); -+ dump_to_cache(f, buf, buflen, dom, path, eep); - if (eep == NULL) - return; - exportent_release(eep); - free(eep); - } - #else /* !HAVE_NFS_PLUGIN_H */ --static void lookup_nonexport(FILE *f, char *dom, char *path, -+static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, - struct addrinfo *UNUSED(ai)) - { -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, buf, buflen, dom, path, NULL); - } - #endif /* !HAVE_NFS_PLUGIN_H */ - --static void nfsd_export(FILE *f) -+static void nfsd_export(int f) - { - /* requests are: - * domain path -@@ -1273,26 +1295,28 @@ static void nfsd_export(FILE *f) - * domain path expiry flags anonuid anongid fsid - */ - -- char *cp; - char *dom, *path; - nfs_export *found = NULL; - struct addrinfo *ai = NULL; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen; - -- if (readline(fileno(f), &lbuf, &lbuflen) != 1) -- return; -+ blen = read(f, buf, sizeof(buf)); -+ if (blen <= 0 || buf[blen-1] != '\n') return; -+ buf[blen-1] = 0; - -- xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf); -+ xlog(D_CALL, "nfsd_export: inbuf '%s'", buf); - -- cp = lbuf; -- dom = malloc(strlen(cp)); -- path = malloc(strlen(cp)); -+ bp = buf; -+ dom = malloc(blen); -+ path = malloc(blen); - - if (!dom || !path) - goto out; - -- if (qword_get(&cp, dom, strlen(lbuf)) <= 0) -+ if (qword_get(&bp, dom, blen) <= 0) - goto out; -- if (qword_get(&cp, path, strlen(lbuf)) <= 0) -+ if (qword_get(&bp, path, blen) <= 0) - goto out; - - auth_reload(); -@@ -1306,14 +1330,14 @@ static void nfsd_export(FILE *f) - found = lookup_export(dom, path, ai); - - if (found) { -- if (dump_to_cache(f, dom, path, &found->m_export) < 0) { -+ if (dump_to_cache(f, buf, sizeof(buf), dom, path, &found->m_export) < 0) { - xlog(L_WARNING, - "Cannot export %s, possibly unsupported filesystem" - " or fsid= required", path); -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, buf, sizeof(buf), dom, path, NULL); - } - } else -- lookup_nonexport(f, dom, path, ai); -+ lookup_nonexport(f, buf, sizeof(buf), dom, path, ai); - - out: - xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); -@@ -1325,15 +1349,14 @@ static void nfsd_export(FILE *f) - - struct { - char *cache_name; -- void (*cache_handle)(FILE *f); -- FILE *f; -- char vbuf[RPC_CHAN_BUF_SIZE]; -+ void (*cache_handle)(int f); -+ int f; - } cachelist[] = { -- { "auth.unix.ip", auth_unix_ip, NULL, ""}, -- { "auth.unix.gid", auth_unix_gid, NULL, ""}, -- { "nfsd.export", nfsd_export, NULL, ""}, -- { "nfsd.fh", nfsd_fh, NULL, ""}, -- { NULL, NULL, NULL, ""} -+ { "auth.unix.ip", auth_unix_ip, -1 }, -+ { "auth.unix.gid", auth_unix_gid, -1 }, -+ { "nfsd.export", nfsd_export, -1 }, -+ { "nfsd.fh", nfsd_fh, -1 }, -+ { NULL, NULL, -1 } - }; - - extern int manage_gids; -@@ -1350,11 +1373,7 @@ void cache_open(void) - if (!manage_gids && cachelist[i].cache_handle == auth_unix_gid) - continue; - sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name); -- cachelist[i].f = fopen(path, "r+"); -- if (cachelist[i].f != NULL) { -- setvbuf(cachelist[i].f, cachelist[i].vbuf, _IOLBF, -- RPC_CHAN_BUF_SIZE); -- } -+ cachelist[i].f = open(path, O_RDWR); - } - } - -@@ -1366,8 +1385,8 @@ void cache_set_fds(fd_set *fdset) - { - int i; - for (i=0; cachelist[i].cache_name; i++) { -- if (cachelist[i].f) -- FD_SET(fileno(cachelist[i].f), fdset); -+ if (cachelist[i].f >= 0) -+ FD_SET(cachelist[i].f, fdset); - } - } - -@@ -1380,11 +1399,11 @@ int cache_process_req(fd_set *readfds) - int i; - int cnt = 0; - for (i=0; cachelist[i].cache_name; i++) { -- if (cachelist[i].f != NULL && -- FD_ISSET(fileno(cachelist[i].f), readfds)) { -+ if (cachelist[i].f >= 0 && -+ FD_ISSET(cachelist[i].f, readfds)) { - cnt++; - cachelist[i].cache_handle(cachelist[i].f); -- FD_CLR(fileno(cachelist[i].f), readfds); -+ FD_CLR(cachelist[i].f, readfds); - } - } - return cnt; -@@ -1397,14 +1416,14 @@ int cache_process_req(fd_set *readfds) - * % echo $domain $path $[now+DEFAULT_TTL] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel - */ - --static int cache_export_ent(char *domain, struct exportent *exp, char *path) -+static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path) - { -- int err; -- FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); -- if (!f) -- return -1; -+ int f, err; -+ -+ f = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); -+ if (f < 0) return -1; - -- err = dump_to_cache(f, domain, exp->e_path, exp); -+ err = dump_to_cache(f, buf, buflen, domain, exp->e_path, exp); - if (err) { - xlog(L_WARNING, - "Cannot export %s, possibly unsupported filesystem or" -@@ -1445,13 +1464,13 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) - continue; - dev = stb.st_dev; - path[l] = 0; -- dump_to_cache(f, domain, path, exp); -+ dump_to_cache(f, buf, buflen, domain, path, exp); - path[l] = c; - } - break; - } - -- fclose(f); -+ close(f); - return err; - } - -@@ -1462,27 +1481,25 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) - */ - int cache_export(nfs_export *exp, char *path) - { -- char buf[INET6_ADDRSTRLEN]; -- int err; -- FILE *f; -+ char ip[INET6_ADDRSTRLEN]; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen, f; - -- f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w"); -- if (!f) -+ f = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); -+ if (f < 0) - return -1; - -- -- qword_print(f, "nfsd"); -- qword_print(f, -- host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); -- qword_printtimefrom(f, exp->m_export.e_ttl); -- qword_print(f, exp->m_client->m_hostname); -- err = qword_eol(f); -- -- fclose(f); -- -- err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export, path) -- || err; -- return err; -+ bp = buf, blen = sizeof(buf); -+ qword_add(&bp, &blen, "nfsd"); -+ qword_add(&bp, &blen, host_ntop(get_addrlist(exp->m_client, 0), ip, sizeof(ip))); -+ qword_adduint(&bp, &blen, time(0) + exp->m_export.e_ttl); -+ qword_add(&bp, &blen, exp->m_client->m_hostname); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) blen = -1; -+ close(f); -+ if (blen < 0) return -1; -+ -+ return cache_export_ent(buf, sizeof(buf), exp->m_client->m_hostname, &exp->m_export, path); - } - - /** -@@ -1501,27 +1518,33 @@ int cache_export(nfs_export *exp, char *path) - struct nfs_fh_len * - cache_get_filehandle(nfs_export *exp, int len, char *p) - { -- FILE *f = fopen("/proc/fs/nfsd/filehandle", "r+"); -- char buf[200]; -- char *bp = buf; -- int failed; - static struct nfs_fh_len fh; -+ char buf[RPC_CHAN_BUF_SIZE], *bp; -+ int blen, f; -+ -+ f = open("/proc/fs/nfsd/filehandle", O_RDWR); -+ if (f < 0) { -+ f = open("/proc/fs/nfs/filehandle", O_RDWR); -+ if (f < 0) return NULL; -+ } - -- if (!f) -- f = fopen("/proc/fs/nfs/filehandle", "r+"); -- if (!f) -+ bp = buf, blen = sizeof(buf); -+ qword_add(&bp, &blen, exp->m_client->m_hostname); -+ qword_add(&bp, &blen, p); -+ qword_addint(&bp, &blen, len); -+ qword_addeol(&bp, &blen); -+ if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) { -+ close(f); - return NULL; -+ } -+ bp = buf; -+ blen = read(f, buf, sizeof(buf)); -+ close(f); - -- qword_print(f, exp->m_client->m_hostname); -- qword_print(f, p); -- qword_printint(f, len); -- failed = qword_eol(f); -- -- if (!failed) -- failed = (fgets(buf, sizeof(buf), f) == NULL); -- fclose(f); -- if (failed) -+ if (blen <= 0 || buf[blen-1] != '\n') - return NULL; -+ buf[blen-1] = 0; -+ - memset(fh.fh_handle, 0, sizeof(fh.fh_handle)); - fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); - return &fh; -diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am -index 1536065..39a6e6f 100644 ---- a/utils/nfsd/Makefile.am -+++ b/utils/nfsd/Makefile.am -@@ -7,6 +7,7 @@ RPCPREFIX = rpc. - KPREFIX = @kprefix@ - sbin_PROGRAMS = nfsd - -+noinst_HEADERS = nfssvc.h - nfsd_SOURCES = nfsd.c nfssvc.c - nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC) - -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 0675b6a..027e5ac 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - #include "nfslib.h" - #include "xlog.h" -diff --git a/utils/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am -index 7524295..0a2858f 100644 ---- a/utils/nfsdcltrack/Makefile.am -+++ b/utils/nfsdcltrack/Makefile.am -@@ -10,6 +10,8 @@ EXTRA_DIST = $(man8_MANS) - AM_CFLAGS += -D_LARGEFILE64_SOURCE - sbin_PROGRAMS = nfsdcltrack - -+noinst_HEADERS = sqlite.h -+ - nfsdcltrack_SOURCES = nfsdcltrack.c sqlite.c - nfsdcltrack_LDADD = ../../support/nfs/libnfs.a $(LIBSQLITE) $(LIBCAP) - -diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c -index fb45c4a..54cd748 100644 ---- a/utils/nfsdcltrack/sqlite.c -+++ b/utils/nfsdcltrack/sqlite.c -@@ -102,7 +102,7 @@ sqlite_query_schema_version(void) - -1, &stmt, NULL); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "Unable to prepare select statement: %s", -- sqlite3_errstr(ret)); -+ sqlite3_errmsg(dbh)); - ret = 0; - goto out; - } -@@ -111,7 +111,7 @@ sqlite_query_schema_version(void) - ret = sqlite3_step(stmt); - if (ret != SQLITE_ROW) { - xlog(L_ERROR, "Select statement execution failed: %s", -- sqlite3_errstr(ret)); -+ sqlite3_errmsg(dbh)); - ret = 0; - goto out; - } -@@ -324,7 +324,7 @@ sqlite_prepare_dbh(const char *topdir) - ret = sqlite3_busy_timeout(dbh, CLTRACK_SQLITE_BUSY_TIMEOUT); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "Unable to set sqlite busy timeout: %s", -- sqlite3_errstr(ret)); -+ sqlite3_errmsg(dbh)); - goto out_close; - } - -@@ -357,7 +357,7 @@ sqlite_prepare_dbh(const char *topdir) - - return ret; - out_close: -- sqlite3_close_v2(dbh); -+ sqlite3_close(dbh); - dbh = NULL; - return ret; - } -@@ -574,21 +574,21 @@ sqlite_query_reclaiming(const time_t grace_start) - "time < ? OR has_session != 1", -1, &stmt, NULL); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "%s: unable to prepare select statement: %s", -- __func__, sqlite3_errstr(ret)); -+ __func__, sqlite3_errmsg(dbh)); - return ret; - } - - ret = sqlite3_bind_int64(stmt, 1, (sqlite3_int64)grace_start); - if (ret != SQLITE_OK) { - xlog(L_ERROR, "%s: bind int64 failed: %s", -- __func__, sqlite3_errstr(ret)); -+ __func__, sqlite3_errmsg(dbh)); - return ret; - } - - ret = sqlite3_step(stmt); - if (ret != SQLITE_ROW) { - xlog(L_ERROR, "%s: unexpected return code from select: %s", -- __func__, sqlite3_errstr(ret)); -+ __func__, sqlite3_errmsg(dbh)); - return ret; - } - -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index 737a219..91cedfd 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -7,4 +7,4 @@ nfsidmap_SOURCES = nfsidmap.c - nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in --EXTRA_DIST = id_resolver.conf -+EXTRA_DIST = id_resolver.conf $(man8_MANS) -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index e0d31e7..5d62078 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -25,7 +25,7 @@ char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; - - #define PROCKEYS "/proc/keys" - #ifndef DEFAULT_KEYRING --#define DEFAULT_KEYRING "id_resolver" -+#define DEFAULT_KEYRING ".id_resolver" - #endif - - #ifndef PATH_IDMAPDCONF -@@ -209,10 +209,23 @@ static int key_invalidate(char *keystr, int keymask) - *(strchr(buf, ' ')) = '\0'; - sscanf(buf, "%x", &key); - -- if (keyctl_invalidate(key) < 0) { -- xlog_err("keyctl_invalidate(0x%x) failed: %m", key); -- fclose(fp); -- return 1; -+/* older libkeyutils compatibility */ -+#ifndef KEYCTL_INVALIDATE -+#define KEYCTL_INVALIDATE 21 /* invalidate a key */ -+#endif -+ if (keyctl(KEYCTL_INVALIDATE, key) < 0) { -+ if (errno != EOPNOTSUPP) { -+ xlog_err("keyctl_invalidate(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } else { -+ /* older kernel compatibility attempt: */ -+ if (keyctl_revoke(key) < 0) { -+ xlog_err("keyctl_revoke(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ } - } - - keymask &= ~mask; -@@ -316,6 +329,9 @@ int main(int argc, char **argv) - key, type, value, timeout); - } - -+ /* Become a possesor of the to-be-instantiated key to set the key's timeout */ -+ request_key("keyring", DEFAULT_KEYRING, NULL, KEY_SPEC_THREAD_KEYRING); -+ - if (strcmp(type, "uid") == 0) - rc = id_lookup(value, key, USER); - else if (strcmp(type, "gid") == 0) -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index 18e4d27..9f481db 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -558,7 +558,7 @@ print_server_stats(int opt_prt) - ; - } else { - print_numbers(LABEL_srvrpc -- "calls badcalls badclnt badauth xdrcall\n", -+ "calls badcalls badfmt badauth badclnt\n", - srvrpcinfo, 5); - printf("\n"); - } -diff --git a/utils/osd_login/Makefile.am b/utils/osd_login/Makefile.am -index 20c2d8c..ded1fd3 100644 ---- a/utils/osd_login/Makefile.am -+++ b/utils/osd_login/Makefile.am -@@ -4,6 +4,6 @@ - # overridden at config time. - sbindir = /sbin - --sbin_SCRIPTS = osd_login -+dist_sbin_SCRIPTS = osd_login - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am -index dc2bfc4..152b680 100644 ---- a/utils/statd/Makefile.am -+++ b/utils/statd/Makefile.am -@@ -8,7 +8,7 @@ sbin_PROGRAMS = statd sm-notify - dist_sbin_SCRIPTS = start-statd - statd_SOURCES = callback.c notlist.c misc.c monitor.c hostname.c \ - simu.c stat.c statd.c svc_run.c rmtcall.c \ -- notlist.h statd.h system.h version.h -+ notlist.h statd.h system.h - sm_notify_SOURCES = sm-notify.c - - BUILT_SOURCES = $(GENFILES) -@@ -20,7 +20,7 @@ sm_notify_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ - $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - --EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c -+EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c - - if CONFIG_RPCGEN - RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen -diff --git a/utils/statd/start-statd b/utils/statd/start-statd -index ec9383b..14369e5 100755 ---- a/utils/statd/start-statd -+++ b/utils/statd/start-statd -@@ -7,7 +7,7 @@ - PATH="/sbin:/usr/sbin:/bin:/usr/bin" - - # First try systemd if it's installed. --if systemctl --help >/dev/null 2>&1; then -+if [ -d /run/systemd/system ]; then - # Quit only if the call worked. - systemctl start rpc-statd.service && exit - fi diff --git a/nfs-utils-1.3.3-rc1.patch b/nfs-utils-1.3.3-rc1.patch new file mode 100644 index 0000000..363acf5 --- /dev/null +++ b/nfs-utils-1.3.3-rc1.patch @@ -0,0 +1,182 @@ +diff --git a/configure.ac b/configure.ac +index 8e427e3..e61430f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -60,7 +60,6 @@ AC_ARG_WITH(systemd, + [AC_HELP_STRING([--with-systemd@<:@=unit-dir-path@:>@], + [install systemd unit files @<:@Default: no, and path defaults to /usr/lib/systemd/system if not given@:>@])], + test "$withval" = "no" && use_systemd=0 || unitdir=$withval use_systemd=1 +- use_systemd=0 + ) + AM_CONDITIONAL(INSTALL_SYSTEMD, [test "$use_systemd" = 1]) + AC_SUBST(unitdir) +diff --git a/support/nfs/exports.c b/support/nfs/exports.c +index eb782b9..4b17d3c 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -154,6 +154,7 @@ getexportent(int fromkernel, int fromexports) + } + } + ++ xfree(ee.e_hostname); + ee = def_ee; + + /* Check for default client */ +@@ -176,7 +177,6 @@ getexportent(int fromkernel, int fromexports) + if (!has_default_opts) + xlog(L_WARNING, "No options for %s %s: suggest %s(sync) to avoid warning", ee.e_path, exp, exp); + } +- xfree(ee.e_hostname); + ee.e_hostname = xstrdup(hostname); + + if (parseopts(opt, &ee, fromexports && !has_default_subtree_opts, NULL) < 0) +diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service +index 941afe5..a655445 100644 +--- a/systemd/rpc-statd-notify.service ++++ b/systemd/rpc-statd-notify.service +@@ -1,7 +1,7 @@ + [Unit] + Description=Notify NFS peers of a restart + Requires=network-online.target +-After=network-online.target nss-lookup.target ++After=network.target nss-lookup.target + + # if we run an nfs server, it needs to be running before we + # tell clients that it has restarted. +diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man +index bee3f86..a9df1e4 100644 +--- a/tools/mountstats/mountstats.man ++++ b/tools/mountstats/mountstats.man +@@ -10,7 +10,7 @@ mountstats \- Displays various NFS client per-mount statistics + .RB [ \-v | \-\-version ] + .RB [ \-f | \-\-file + .IR infile ] +-.RB [ \-s | \-\-since ++.RB [ \-S | \-\-since + .IR sincefile ] + .\" .RB [ \-n | \-\-nfs | \-r | \-\-rpc | \-R | \-\-raw ] + .R [ +@@ -27,7 +27,7 @@ mountstats \- Displays various NFS client per-mount statistics + .RB [ \-v | \-\-version ] + .RB [ \-f | \-\-file + .IR infile ] +-.RB [ \-s | \-\-since ++.RB [ \-S | \-\-since + .IR sincefile ] + .RI [ interval ] + .RI [ count ] +@@ -38,7 +38,7 @@ mountstats \- Displays various NFS client per-mount statistics + .RB [ \-v | \-\-version ] + .RB [ \-f | \-\-file + .IR infile ] +-.RB [ \-s | \-\-since ++.RB [ \-S | \-\-since + .IR sincefile ] + .RB [ \-3 ] + .RB [ \-4 ] +@@ -128,7 +128,7 @@ parameter is specified without the + parameter, the command generates reports continuously. This may not be used with the + .BR \-f | \-\-file + or +-.BR \-s | \-\-since ++.BR \-S | \-\-since + options. + .SS Options specific to the nfsstat sub-command + .IP "\fB\-3\fP" +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index 3d974d9..88d9fbe 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -218,16 +218,46 @@ This option can be very useful in some situations, but it should be + used with due care, and only after confirming that the client system + copes with the situation effectively. + +-The option can be explicitly disabled with ++The option can be explicitly disabled for NFSv2 and NFSv3 with + .IR hide . ++ ++This option is not relevant when NFSv4 is use. NFSv4 never hides ++subordinate filesystems. Any filesystem that is exported will be ++visible where expected when using NFSv4. + .TP +-.IR crossmnt ++.I crossmnt + This option is similar to + .I nohide +-but it makes it possible for clients to move from the filesystem marked +-with crossmnt to exported filesystems mounted on it. Thus when a child +-filesystem "B" is mounted on a parent "A", setting crossmnt on "A" has +-the same effect as setting "nohide" on B. ++but it makes it possible for clients to access all filesystems mounted ++on a filesystem marked with ++.IR crossmnt . ++Thus when a child filesystem "B" is mounted on a parent "A", setting ++crossmnt on "A" has a similar effect to setting "nohide" on B. ++ ++With ++.I nohide ++the child filesystem needs to be explicitly exported. With ++.I crossmnt ++it need not. If a child of a ++.I crossmnt ++file is not explicitly exported, then it will be implicitly exported ++with the same export options as the parent, except for ++.IR fsid= . ++This makes it impossible to ++.B not ++export a child of a ++.I crossmnt ++filesystem. If some but not all subordinate filesystems of a parent ++are to be exported, then they must be explicitly exported and the ++parent should not have ++.I crossmnt ++set. ++ ++The ++.I nocrossmnt ++option can explictly disable ++.I crossmnt ++if it was previously set. This is rarely useful. + .TP + .IR no_subtree_check + This option disables subtree checking, which has mild security +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index c23d384..7d250f9 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -376,7 +376,7 @@ static char *next_mnt(void **v, char *p) + *v = f; + } else + f = *v; +- while ((me = getmntent(f)) != NULL && ++ while ((me = getmntent(f)) != NULL && l > 1 && + (strncmp(me->mnt_dir, p, l) != 0 || + me->mnt_dir[l] != '/')) + ; +diff --git a/utils/statd/rmtcall.c b/utils/statd/rmtcall.c +index fd576d9..66a6eeb 100644 +--- a/utils/statd/rmtcall.c ++++ b/utils/statd/rmtcall.c +@@ -221,6 +221,9 @@ process_reply(FD_SET_TYPE *rfds) + if (sockfd == -1 || !FD_ISSET(sockfd, rfds)) + return 0; + ++ /* Should not be processed again. */ ++ FD_CLR (sockfd, rfds); ++ + if (!(lp = recv_rply(&port))) + return 1; + +diff --git a/utils/statd/statd.c b/utils/statd/statd.c +index 60ce6d1..2b7a167 100644 +--- a/utils/statd/statd.c ++++ b/utils/statd/statd.c +@@ -393,7 +393,7 @@ int main (int argc, char **argv) + simulator (--argc, ++argv); /* simulator() does exit() */ + #endif + +- daemon_init(!(run_mode & MODE_NODAEMON)); ++ daemon_init((run_mode & MODE_NODAEMON)); + + if (run_mode & MODE_LOG_STDERR) { + xlog_syslog(0); diff --git a/nfs-utils.1.2.9-rc4.patch b/nfs-utils.1.2.9-rc4.patch deleted file mode 100644 index ea4ebe6..0000000 --- a/nfs-utils.1.2.9-rc4.patch +++ /dev/null @@ -1,1446 +0,0 @@ -diff --git a/support/include/conffile.h b/support/include/conffile.h -index ce7aa21..05ea5d2 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -54,7 +54,7 @@ extern int conf_end(int, int); - extern void conf_free_list(struct conf_list *); - extern struct sockaddr *conf_get_address(char *, char *); - extern struct conf_list *conf_get_list(char *, char *); --extern struct conf_list *conf_get_tag_list(char *); -+extern struct conf_list *conf_get_tag_list(char *, char *); - extern int conf_get_num(char *, char *, int); - extern char *conf_get_str(char *, char *); - extern char *conf_get_section(char *, char *, char *); -diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h -index 174c2dd..38db5b5 100644 ---- a/support/include/nfs/nfs.h -+++ b/support/include/nfs/nfs.h -@@ -15,6 +15,10 @@ - #define NFSD_MINVERS 2 - #define NFSD_MAXVERS 4 - -+#define NFS4_MINMINOR 1 -+#define NFS4_MAXMINOR 2 -+#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */ -+ - struct nfs_fh_len { - int fh_size; - u_int8_t fh_handle[NFS3_FHSIZE]; -@@ -52,6 +56,7 @@ struct nfs_fh_old { - #define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) - #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) - -+#define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ - #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) - #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) - #define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index a0b80e1..1bfae7a 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -156,6 +156,11 @@ extern unsigned long nfs_pmap_getport(const struct sockaddr_in *, - const struct timeval *); - - /* -+ * Use nfs_pmap_getport to see if statd is running locally -+ */ -+extern int nfs_probe_statd(void); -+ -+/* - * Contact a remote RPC service to discover whether it is responding - * to requests. - */ -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 5015e94..c3434d5 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -565,7 +565,7 @@ cleanup: - } - - struct conf_list * --conf_get_tag_list(char *section) -+conf_get_tag_list(char *section, char *arg) - { - struct conf_list *list = 0; - struct conf_list_node *node; -@@ -579,6 +579,8 @@ conf_get_tag_list(char *section) - cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); - for (; cb; cb = LIST_NEXT(cb, link)) { - if (strcasecmp (section, cb->section) == 0) { -+ if (arg != NULL && strcasecmp(arg, cb->arg) != 0) -+ continue; - list->cnt++; - node = calloc(1, sizeof *node); - if (!node) -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index dea040f..05178f7 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -196,10 +196,35 @@ getexportent(int fromkernel, int fromexports) - return ⅇ - } - -+static const struct secinfo_flag_displaymap { -+ unsigned int flag; -+ const char *set; -+ const char *unset; -+} secinfo_flag_displaymap[] = { -+ { NFSEXP_READONLY, "ro", "rw" }, -+ { NFSEXP_INSECURE_PORT, "insecure", "secure" }, -+ { NFSEXP_ROOTSQUASH, "root_squash", "no_root_squash" }, -+ { NFSEXP_ALLSQUASH, "all_squash", "no_all_squash" }, -+ { 0, NULL, NULL } -+}; -+ -+static void secinfo_flags_show(FILE *fp, unsigned int flags, unsigned int mask) -+{ -+ const struct secinfo_flag_displaymap *p; -+ -+ for (p = &secinfo_flag_displaymap[0]; p->flag != 0; p++) { -+ if (!(mask & p->flag)) -+ continue; -+ fprintf(fp, ",%s", (flags & p->flag) ? p->set : p->unset); -+ } -+} -+ - void secinfo_show(FILE *fp, struct exportent *ep) - { -+ const struct export_features *ef; - struct sec_entry *p1, *p2; -- int flags; -+ -+ ef = get_export_features(); - - for (p1=ep->e_secinfo; p1->flav; p1=p2) { - -@@ -208,12 +233,7 @@ void secinfo_show(FILE *fp, struct exportent *ep) - p2++) { - fprintf(fp, ":%s", p2->flav->flavour); - } -- flags = p1->flags; -- fprintf(fp, ",%s", (flags & NFSEXP_READONLY) ? "ro" : "rw"); -- fprintf(fp, ",%sroot_squash", (flags & NFSEXP_ROOTSQUASH)? -- "" : "no_"); -- fprintf(fp, ",%sall_squash", (flags & NFSEXP_ALLSQUASH)? -- "" : "no_"); -+ secinfo_flags_show(fp, p1->flags, ef->secinfo_flags); - } - } - -diff --git a/support/nfs/getport.c b/support/nfs/getport.c -index 3331ad4..081594c 100644 ---- a/support/nfs/getport.c -+++ b/support/nfs/getport.c -@@ -1102,3 +1102,25 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, - - return port; - } -+ -+static const char *nfs_ns_pgmtbl[] = { -+ "status", -+ NULL, -+}; -+ -+/* -+ * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally -+ * -+ * Returns non-zero if statd is running locally. -+ */ -+int nfs_probe_statd(void) -+{ -+ struct sockaddr_in addr = { -+ .sin_family = AF_INET, -+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -+ }; -+ rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -+ -+ return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr), -+ program, (rpcvers_t)1, IPPROTO_UDP); -+} -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index b95b71d..3f5fea5 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -53,7 +53,7 @@ class DeviceData: - if words[6].find('nfs') != -1: - self.__nfs_data['statvers'] = words[7] - elif words[0] == 'age:': -- self.__nfs_data['age'] = long(words[1]) -+ self.__nfs_data['age'] = int(words[1]) - elif words[0] == 'opts:': - self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',') - elif words[0] == 'caps:': -@@ -91,12 +91,12 @@ class DeviceData: - self.__nfs_data['shortwrites'] = int(words[22]) - self.__nfs_data['delay'] = int(words[23]) - elif words[0] == 'bytes:': -- self.__nfs_data['normalreadbytes'] = long(words[1]) -- self.__nfs_data['normalwritebytes'] = long(words[2]) -- self.__nfs_data['directreadbytes'] = long(words[3]) -- self.__nfs_data['directwritebytes'] = long(words[4]) -- self.__nfs_data['serverreadbytes'] = long(words[5]) -- self.__nfs_data['serverwritebytes'] = long(words[6]) -+ self.__nfs_data['normalreadbytes'] = int(words[1]) -+ self.__nfs_data['normalwritebytes'] = int(words[2]) -+ self.__nfs_data['directreadbytes'] = int(words[3]) -+ self.__nfs_data['directwritebytes'] = int(words[4]) -+ self.__nfs_data['serverreadbytes'] = int(words[5]) -+ self.__nfs_data['serverwritebytes'] = int(words[6]) - - def __parse_rpc_line(self, words): - if words[0] == 'RPC': -@@ -110,8 +110,8 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[4]) - self.__rpc_data['rpcreceives'] = int(words[5]) - self.__rpc_data['badxids'] = int(words[6]) -- self.__rpc_data['inflightsends'] = long(words[7]) -- self.__rpc_data['backlogutil'] = long(words[8]) -+ self.__rpc_data['inflightsends'] = int(words[7]) -+ self.__rpc_data['backlogutil'] = int(words[8]) - elif words[1] == 'tcp': - self.__rpc_data['port'] = words[2] - self.__rpc_data['bind_count'] = int(words[3]) -@@ -121,7 +121,7 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[7]) - self.__rpc_data['rpcreceives'] = int(words[8]) - self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['inflightsends'] = long(words[10]) -+ self.__rpc_data['inflightsends'] = int(words[10]) - self.__rpc_data['backlogutil'] = int(words[11]) - elif words[1] == 'rdma': - self.__rpc_data['port'] = words[2] -@@ -148,7 +148,7 @@ class DeviceData: - else: - op = words[0][:-1] - self.__rpc_data['ops'] += [op] -- self.__rpc_data[op] = [long(word) for word in words[1:]] -+ self.__rpc_data[op] = [int(word) for word in words[1:]] - - def parse_stats(self, lines): - """Turn a list of lines from a mount stat file into a -@@ -179,81 +179,81 @@ class DeviceData: - def display_nfs_options(self): - """Pretty-print the NFS options - """ -- print 'Stats for %s mounted on %s:' % \ -- (self.__nfs_data['export'], self.__nfs_data['mountpoint']) -- -- print ' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions']) -- print ' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities']) -- if self.__nfs_data.has_key('nfsv4flags'): -- print ' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags']) -- if self.__nfs_data.has_key('pseudoflavor'): -- print ' NFS security flavor: %d pseudoflavor: %d' % \ -- (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor']) -+ print('Stats for %s mounted on %s:' % \ -+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) -+ -+ print(' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])) -+ print(' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])) -+ if 'nfsv4flags' in self.__nfs_data: -+ print(' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags'])) -+ if 'pseudoflavor' in self.__nfs_data: -+ print(' NFS security flavor: %d pseudoflavor: %d' % \ -+ (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor'])) - else: -- print ' NFS security flavor: %d' % self.__nfs_data['flavor'] -+ print(' NFS security flavor: %d' % self.__nfs_data['flavor']) - - def display_nfs_events(self): - """Pretty-print the NFS event counters - """ -- print -- print 'Cache events:' -- print ' data cache invalidated %d times' % self.__nfs_data['datainvalidates'] -- print ' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates'] -- print ' inodes synced %d times' % self.__nfs_data['syncinodes'] -- print -- print 'VFS calls:' -- print ' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates'] -- print ' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates'] -- print -- print ' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir'] -- print ' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup'] -- print ' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission'] -- print ' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen'] -- print ' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush'] -- print ' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock'] -- print ' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync'] -- print ' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease'] -- print -- print 'VM calls:' -- print ' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage'] -- print ' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages'] -- print ' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage'] -- print ' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages'] -- print -- print 'Generic NFS counters:' -- print ' File size changing operations:' -- print ' truncating SETATTRs: %d extending WRITEs: %d' % \ -- (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite']) -- print ' %d silly renames' % self.__nfs_data['sillyrenames'] -- print ' short reads: %d short writes: %d' % \ -- (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites']) -- print ' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay'] -+ print() -+ print('Cache events:') -+ print(' data cache invalidated %d times' % self.__nfs_data['datainvalidates']) -+ print(' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']) -+ print(' inodes synced %d times' % self.__nfs_data['syncinodes']) -+ print() -+ print('VFS calls:') -+ print(' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']) -+ print(' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates']) -+ print() -+ print(' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir']) -+ print(' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup']) -+ print(' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission']) -+ print(' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen']) -+ print(' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush']) -+ print(' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock']) -+ print(' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync']) -+ print(' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease']) -+ print() -+ print('VM calls:') -+ print(' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage']) -+ print(' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages']) -+ print(' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage']) -+ print(' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages']) -+ print() -+ print('Generic NFS counters:') -+ print(' File size changing operations:') -+ print(' truncating SETATTRs: %d extending WRITEs: %d' % \ -+ (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite'])) -+ print(' %d silly renames' % self.__nfs_data['sillyrenames']) -+ print(' short reads: %d short writes: %d' % \ -+ (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])) -+ print(' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']) - - def display_nfs_bytes(self): - """Pretty-print the NFS event counters - """ -- print -- print 'NFS byte counts:' -- print ' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes'] -- print ' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes'] -- print ' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes'] -- print ' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes'] -- print ' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes'] -- print ' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes'] -+ print() -+ print('NFS byte counts:') -+ print(' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes']) -+ print(' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes']) -+ print(' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes']) -+ print(' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes']) -+ print(' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes']) -+ print(' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes']) - - def display_rpc_generic_stats(self): - """Pretty-print the generic RPC stats - """ - sends = self.__rpc_data['rpcsends'] - -- print -- print 'RPC statistics:' -+ print() -+ print('RPC statistics:') - -- print ' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ -- (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids']) -+ print(' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ -+ (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids'])) - if sends != 0: -- print ' average backlog queue length: %d' % \ -- (float(self.__rpc_data['backlogutil']) / sends) -+ print(' average backlog queue length: %d' % \ -+ (float(self.__rpc_data['backlogutil']) / sends)) - - def display_rpc_op_stats(self): - """Pretty-print the per-op stats -@@ -261,23 +261,23 @@ class DeviceData: - sends = self.__rpc_data['rpcsends'] - - # XXX: these should be sorted by 'count' -- print -+ print() - for op in self.__rpc_data['ops']: - stats = self.__rpc_data[op] - count = stats[0] - retrans = stats[1] - count - if count != 0: -- print '%s:' % op -- print '\t%d ops (%d%%)' % \ -- (count, ((count * 100) / sends)), -- print '\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), -- print '\t%d major timeouts' % stats[2] -- print '\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ -- (stats[3] / count, stats[4] / count) -- print '\tbacklog wait: %f' % (float(stats[5]) / count), -- print '\tRTT: %f' % (float(stats[6]) / count), -- print '\ttotal execute time: %f (milliseconds)' % \ -- (float(stats[7]) / count) -+ print('%s:' % op) -+ print('\t%d ops (%d%%)' % \ -+ (count, ((count * 100) / sends)), end=' ') -+ print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') -+ print('\t%d major timeouts' % stats[2]) -+ print('\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ -+ (stats[3] / count, stats[4] / count)) -+ print('\tbacklog wait: %f' % (float(stats[5]) / count), end=' ') -+ print('\tRTT: %f' % (float(stats[6]) / count), end=' ') -+ print('\ttotal execute time: %f (milliseconds)' % \ -+ (float(stats[7]) / count)) - - def compare_iostats(self, old_stats): - """Return the difference between two sets of stats -@@ -285,9 +285,9 @@ class DeviceData: - result = DeviceData() - - # copy self into result -- for key, value in self.__nfs_data.iteritems(): -+ for key, value in self.__nfs_data.items(): - result.__nfs_data[key] = value -- for key, value in self.__rpc_data.iteritems(): -+ for key, value in self.__rpc_data.items(): - result.__rpc_data[key] = value - - # compute the difference of each item in the list -@@ -295,7 +295,7 @@ class DeviceData: - # the reference to them. so we build new lists here - # for the result object. - for op in result.__rpc_data['ops']: -- result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]) -+ result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) - - # update the remaining keys we care about - result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -@@ -312,17 +312,17 @@ class DeviceData: - if sample_time == 0: - sample_time = float(self.__nfs_data['age']) - -- print -- print '%s mounted on %s:' % \ -- (self.__nfs_data['export'], self.__nfs_data['mountpoint']) -+ print() -+ print('%s mounted on %s:' % \ -+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) - -- print '\top/s\trpc bklog' -- print '\t%.2f' % (sends / sample_time), -+ print('\top/s\trpc bklog') -+ print('\t%.2f' % (sends / sample_time), end=' ') - if sends != 0: -- print '\t%.2f' % \ -- ((float(self.__rpc_data['backlogutil']) / sends) / sample_time) -+ print('\t%.2f' % \ -+ ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)) - else: -- print '\t0.00' -+ print('\t0.00') - - # reads: ops/s, kB/s, avg rtt, and avg exe - # XXX: include avg xfer size and retransmits? -@@ -332,15 +332,15 @@ class DeviceData: - rtt = float(read_rpc_stats[6]) - exe = float(read_rpc_stats[7]) - -- print '\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)' -- print '\t\t%.2f' % (ops / sample_time), -- print '\t\t%.2f' % (kilobytes / sample_time), -+ print('\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -+ print('\t\t%.2f' % (ops / sample_time), end=' ') -+ print('\t\t%.2f' % (kilobytes / sample_time), end=' ') - if ops != 0: -- print '\t\t%.2f' % (rtt / ops), -- print '\t\t%.2f' % (exe / ops) -+ print('\t\t%.2f' % (rtt / ops), end=' ') -+ print('\t\t%.2f' % (exe / ops)) - else: -- print '\t\t0.00', -- print '\t\t0.00' -+ print('\t\t0.00', end=' ') -+ print('\t\t0.00') - - # writes: ops/s, kB/s, avg rtt, and avg exe - # XXX: include avg xfer size and retransmits? -@@ -350,15 +350,15 @@ class DeviceData: - rtt = float(write_rpc_stats[6]) - exe = float(write_rpc_stats[7]) - -- print '\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)' -- print '\t\t%.2f' % (ops / sample_time), -- print '\t\t%.2f' % (kilobytes / sample_time), -+ print('\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -+ print('\t\t%.2f' % (ops / sample_time), end=' ') -+ print('\t\t%.2f' % (kilobytes / sample_time), end=' ') - if ops != 0: -- print '\t\t%.2f' % (rtt / ops), -- print '\t\t%.2f' % (exe / ops) -+ print('\t\t%.2f' % (rtt / ops), end=' ') -+ print('\t\t%.2f' % (exe / ops)) - else: -- print '\t\t0.00', -- print '\t\t0.00' -+ print('\t\t0.00', end=' ') -+ print('\t\t0.00') - - def parse_stats_file(filename): - """pop the contents of a mountstats file into a dictionary, -@@ -388,18 +388,18 @@ def parse_stats_file(filename): - return ms_dict - - def print_mountstats_help(name): -- print 'usage: %s [ options ] ' % name -- print -- print ' Version %s' % Mountstats_version -- print -- print ' Display NFS client per-mount statistics.' -- print -- print ' --version display the version of this command' -- print ' --nfs display only the NFS statistics' -- print ' --rpc display only the RPC statistics' -- print ' --start sample and save statistics' -- print ' --end resample statistics and compare them with saved' -- print -+ print('usage: %s [ options ] ' % name) -+ print() -+ print(' Version %s' % Mountstats_version) -+ print() -+ print(' Display NFS client per-mount statistics.') -+ print() -+ print(' --version display the version of this command') -+ print(' --nfs display only the NFS statistics') -+ print(' --rpc display only the RPC statistics') -+ print(' --start sample and save statistics') -+ print(' --end resample statistics and compare them with saved') -+ print() - - def mountstats_command(): - """Mountstats command -@@ -414,7 +414,7 @@ def mountstats_command(): - return - - if arg in ['-v', '--version', 'version']: -- print '%s version %s' % (sys.argv[0], Mountstats_version) -+ print('%s version %s' % (sys.argv[0], Mountstats_version)) - sys.exit(0) - - if arg in ['-n', '--nfs']: -@@ -426,10 +426,10 @@ def mountstats_command(): - continue - - if arg in ['-s', '--start']: -- raise Exception, 'Sampling is not yet implemented' -+ raise Exception('Sampling is not yet implemented') - - if arg in ['-e', '--end']: -- raise Exception, 'Sampling is not yet implemented' -+ raise Exception('Sampling is not yet implemented') - - if arg == sys.argv[0]: - continue -@@ -448,14 +448,14 @@ def mountstats_command(): - - for mp in mountpoints: - if mp not in mountstats: -- print 'Statistics for mount point %s not found' % mp -+ print('Statistics for mount point %s not found' % mp) - continue - - stats = DeviceData() - stats.parse_stats(mountstats[mp]) - - if not stats.is_nfs_mountpoint(): -- print 'Mount point %s exists but is not an NFS mount' % mp -+ print('Mount point %s exists but is not an NFS mount' % mp) - continue - - if nfs_only: -@@ -472,37 +472,37 @@ def mountstats_command(): - stats.display_rpc_op_stats() - - def print_nfsstat_help(name): -- print 'usage: %s [ options ]' % name -- print -- print ' Version %s' % Mountstats_version -- print -- print ' nfsstat-like program that uses NFS client per-mount statistics.' -- print -+ print('usage: %s [ options ]' % name) -+ print() -+ print(' Version %s' % Mountstats_version) -+ print() -+ print(' nfsstat-like program that uses NFS client per-mount statistics.') -+ print() - - def nfsstat_command(): - print_nfsstat_help(prog) - - def print_iostat_help(name): -- print 'usage: %s [ [ ] ] [ ] ' % name -- print -- print ' Version %s' % Mountstats_version -- print -- print ' iostat-like program to display NFS client per-mount statistics.' -- print -- print ' The parameter specifies the amount of time in seconds between' -- print ' each report. The first report contains statistics for the time since each' -- print ' file system was mounted. Each subsequent report contains statistics' -- print ' collected during the interval since the previous report.' -- print -- print ' If the parameter is specified, the value of determines the' -- print ' number of reports generated at seconds apart. If the interval' -- print ' parameter is specified without the parameter, the command generates' -- print ' reports continuously.' -- print -- print ' If one or more names are specified, statistics for only these' -- print ' mount points will be displayed. Otherwise, all NFS mount points on the' -- print ' client are listed.' -- print -+ print('usage: %s [ [ ] ] [ ] ' % name) -+ print() -+ print(' Version %s' % Mountstats_version) -+ print() -+ print(' iostat-like program to display NFS client per-mount statistics.') -+ print() -+ print(' The parameter specifies the amount of time in seconds between') -+ print(' each report. The first report contains statistics for the time since each') -+ print(' file system was mounted. Each subsequent report contains statistics') -+ print(' collected during the interval since the previous report.') -+ print() -+ print(' If the parameter is specified, the value of determines the') -+ print(' number of reports generated at seconds apart. If the interval') -+ print(' parameter is specified without the parameter, the command generates') -+ print(' reports continuously.') -+ print() -+ print(' If one or more names are specified, statistics for only these') -+ print(' mount points will be displayed. Otherwise, all NFS mount points on the') -+ print(' client are listed.') -+ print() - - def print_iostat_summary(old, new, devices, time): - for device in devices: -@@ -530,7 +530,7 @@ def iostat_command(): - return - - if arg in ['-v', '--version', 'version']: -- print '%s version %s' % (sys.argv[0], Mountstats_version) -+ print('%s version %s' % (sys.argv[0], Mountstats_version)) - return - - if arg == sys.argv[0]: -@@ -543,14 +543,14 @@ def iostat_command(): - if interval > 0: - interval_seen = True - else: -- print 'Illegal value' -+ print('Illegal value') - return - elif not count_seen: - count = int(arg) - if count > 0: - count_seen = True - else: -- print 'Illegal value' -+ print('Illegal value') - return - - # make certain devices contains only NFS mount points -@@ -563,13 +563,13 @@ def iostat_command(): - check += [device] - devices = check - else: -- for device, descr in mountstats.iteritems(): -+ for device, descr in mountstats.items(): - stats = DeviceData() - stats.parse_stats(descr) - if stats.is_nfs_mountpoint(): - devices += [device] - if len(devices) == 0: -- print 'No NFS mount points were found' -+ print('No NFS mount points were found') - return - - old_mountstats = None -@@ -608,7 +608,7 @@ try: - elif prog == 'ms-iostat': - iostat_command() - except KeyboardInterrupt: -- print 'Caught ^C... exiting' -+ print('Caught ^C... exiting') - sys.exit(1) - - sys.exit(0) -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index dfbef87..341cdbf 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -95,7 +95,7 @@ class DeviceData: - if words[6] == 'nfs': - self.__nfs_data['statvers'] = words[7] - elif words[0] == 'age:': -- self.__nfs_data['age'] = long(words[1]) -+ self.__nfs_data['age'] = int(words[1]) - elif words[0] == 'opts:': - self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',') - elif words[0] == 'caps:': -@@ -116,7 +116,7 @@ class DeviceData: - elif words[0] == 'bytes:': - i = 1 - for key in NfsByteCounters: -- self.__nfs_data[key] = long(words[i]) -+ self.__nfs_data[key] = int(words[i]) - i += 1 - - def __parse_rpc_line(self, words): -@@ -131,8 +131,8 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[4]) - self.__rpc_data['rpcreceives'] = int(words[5]) - self.__rpc_data['badxids'] = int(words[6]) -- self.__rpc_data['inflightsends'] = long(words[7]) -- self.__rpc_data['backlogutil'] = long(words[8]) -+ self.__rpc_data['inflightsends'] = int(words[7]) -+ self.__rpc_data['backlogutil'] = int(words[8]) - elif words[1] == 'tcp': - self.__rpc_data['port'] = words[2] - self.__rpc_data['bind_count'] = int(words[3]) -@@ -142,8 +142,8 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[7]) - self.__rpc_data['rpcreceives'] = int(words[8]) - self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['inflightsends'] = long(words[10]) -- self.__rpc_data['backlogutil'] = long(words[11]) -+ self.__rpc_data['inflightsends'] = int(words[10]) -+ self.__rpc_data['backlogutil'] = int(words[11]) - elif words[1] == 'rdma': - self.__rpc_data['port'] = words[2] - self.__rpc_data['bind_count'] = int(words[3]) -@@ -169,7 +169,7 @@ class DeviceData: - else: - op = words[0][:-1] - self.__rpc_data['ops'] += [op] -- self.__rpc_data[op] = [long(word) for word in words[1:]] -+ self.__rpc_data[op] = [int(word) for word in words[1:]] - - def parse_stats(self, lines): - """Turn a list of lines from a mount stat file into a -@@ -271,7 +271,7 @@ class DeviceData: - nfs_stats = self.__nfs_data - lookup_ops = self.__rpc_data['LOOKUP'][0] - readdir_ops = self.__rpc_data['READDIR'][0] -- if self.__rpc_data.has_key('READDIRPLUS'): -+ if 'READDIRPLUS' in self.__rpc_data: - readdir_ops += self.__rpc_data['READDIRPLUS'][0] - - dentry_revals = nfs_stats['dentryrevalidates'] -@@ -330,7 +330,7 @@ class DeviceData: - def __print_rpc_op_stats(self, op, sample_time): - """Print generic stats for one RPC op - """ -- if not self.__rpc_data.has_key(op): -+ if op not in self.__rpc_data: - return - - rpc_stats = self.__rpc_data[op] -@@ -353,14 +353,14 @@ class DeviceData: - exe_per_op = 0.0 - - op += ':' -- print('%s' % op.lower().ljust(15)) -+ print('%s' % op.lower().ljust(15), end='') - print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') - -- print('\t\t%7.3f' % (ops / sample_time)) -- print('\t%7.3f' % (kilobytes / sample_time)) -- print('\t%7.3f' % kb_per_op) -- print(' %7d (%3.1f%%)' % (retrans, retrans_percent)) -- print('\t%7.3f' % rtt_per_op) -+ print('\t\t%7.3f' % (ops / sample_time), end='') -+ print('\t%7.3f' % (kilobytes / sample_time), end='') -+ print('\t%7.3f' % kb_per_op, end='') -+ print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') -+ print('\t%7.3f' % rtt_per_op, end='') - print('\t%7.3f' % exe_per_op) - - def ops(self, sample_time): -@@ -392,7 +392,7 @@ class DeviceData: - print() - - print(' op/s\t\trpc bklog') -- print('%7.2f' % (sends / sample_time)) -+ print('%7.2f' % (sends / sample_time), end='') - print('\t%7.2f' % backlog) - - if which == 0: -@@ -405,7 +405,7 @@ class DeviceData: - elif which == 2: - self.__print_rpc_op_stats('LOOKUP', sample_time) - self.__print_rpc_op_stats('READDIR', sample_time) -- if self.__rpc_data.has_key('READDIRPLUS'): -+ if 'READDIRPLUS' in self.__rpc_data: - self.__print_rpc_op_stats('READDIRPLUS', sample_time) - self.__print_dir_cache_stats(sample_time) - elif which == 3: -@@ -413,6 +413,8 @@ class DeviceData: - self.__print_rpc_op_stats('WRITE', sample_time) - self.__print_page_stats(sample_time) - -+ sys.stdout.flush() -+ - # - # Functions - # -@@ -450,7 +452,7 @@ def print_iostat_summary(old, new, devices, time, options): - if old: - # Trim device list to only include intersection of old and new data, - # this addresses umounts due to autofs mountpoints -- devicelist = filter(lambda x:x in devices,old) -+ devicelist = [x for x in old if x in devices] - else: - devicelist = devices - -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index bc1de73..58c0f66 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -39,7 +39,7 @@ the export name using a backslash followed by the character code as three - octal digits. - .PP - To apply changes to this file, run --.BR exportfs \-ra -+.BR "exportfs \-ra" - or restart the NFS server. - .PP - .SS Machine Name Formats -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 1df75c5..ac13fd4 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -195,11 +195,28 @@ option when starting - .BR rpc.gssd . - .SH OPTIONS - .TP --.B -D --DNS Reverse lookups are not used for determining the --server names pass to GSSAPI. This option will reverses that and forces --the use of DNS Reverse resolution of the server's IP address to --retrieve the server name to use in GSAPI authentication. -+.B \-D -+The server name passed to GSSAPI for authentication is normally the -+name exactly as requested. e.g. for NFS -+it is the server name in the "servername:/path" mount request. Only if this -+servername appears to be an IP address (IPv4 or IPv6) or an -+unqualified name (no dots) will a reverse DNS lookup -+will be performed to get the canoncial server name. -+ -+If -+.B \-D -+is present, a reverse DNS lookup will -+.I always -+be used, even if the server name looks like a canonical name. So it -+is needed if partially qualified, or non canonical names are regularly -+used. -+ -+Using -+.B \-D -+can introduce a security vulnerability, so it is recommended that -+.B \-D -+not be used, and that canonical names always be used when requesting -+services. - .TP - .B -f - Runs -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index af1844c..2d3dbec 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -67,7 +67,6 @@ - #include - #include - #include --#include - - #include "gssd.h" - #include "err_util.h" -@@ -176,7 +175,6 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - char *hostname; - char hbuf[NI_MAXHOST]; - unsigned char buf[sizeof(struct in6_addr)]; -- int servername = 0; - - if (avoid_dns) { - /* -@@ -184,15 +182,18 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - * If it is an IP address, do the DNS lookup otherwise - * skip the DNS lookup. - */ -- servername = 0; -- if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1) -- servername = 1; /* IPv4 */ -- else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1) -- servername = 1; /* or IPv6 */ -- -- if (servername) { -+ int is_fqdn = 1; -+ if (strchr(name, '.') == NULL) -+ is_fqdn = 0; /* local name */ -+ else if (inet_pton(AF_INET, name, buf) == 1) -+ is_fqdn = 0; /* IPv4 address */ -+ else if (inet_pton(AF_INET6, name, buf) == 1) -+ is_fqdn = 0; /* IPv6 addrss */ -+ -+ if (is_fqdn) { - return strdup(name); - } -+ /* Sorry, cannot avoid dns after all */ - } - - switch (sa->sa_family) { -@@ -466,8 +467,9 @@ process_clnt_dir(char *dir, char *pdir) - } - sprintf(clp->dirname, "%s/%s", pdir, dir); - if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) { -- printerr(0, "ERROR: can't open %s: %s\n", -- clp->dirname, strerror(errno)); -+ if (errno != ENOENT) -+ printerr(0, "ERROR: can't open %s: %s\n", -+ clp->dirname, strerror(errno)); - goto fail_destroy_client; - } - fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL); -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 6275dd8..83b9651 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -231,7 +231,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, - continue; - } - if (uid == 0 && !root_uses_machine_creds && -- strstr(namelist[i]->d_name, "_machine_")) { -+ strstr(namelist[i]->d_name, "machine_")) { - printerr(3, "CC '%s' not available to root\n", - statname); - free(namelist[i]); -@@ -825,8 +825,10 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - - retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) -- goto out; -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - - code = krb5_get_default_realm(context, &default_realm); - if (code) { -@@ -852,11 +854,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - } - - /* -- * Try the "appropriate" realm first, and if nothing found for that -- * realm, try the default realm (if it hasn't already been tried). -+ * Make sure the preferred_realm, which may have been explicitly set -+ * on the command line, is tried first. If nothing is found go on with -+ * the host and local default realm (if that hasn't already been tried). - */ - i = 0; - realm = realmnames[i]; -+ -+ if (strcmp (realm, preferred_realm) != 0) { -+ realm = preferred_realm; -+ /* resetting the realmnames index */ -+ i = -1; -+ } -+ - while (1) { - if (realm == NULL) { - tried_all = 1; -@@ -883,6 +893,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad, - NULL); - } else { -+ if (!myhostname[0]) -+ continue; - snprintf(spn, sizeof(spn), "%s/%s@%s", - svcnames[j], myhostname, realm); - code = krb5_build_principal_ext(context, &princ, -@@ -1236,7 +1248,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, - krb5_keytab kt = NULL;; - int retval = 0; - char *k5err = NULL; -- const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; -+ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - - /* - * If a specific service name was specified, use it. -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index beba9c4..b6c6231 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -502,7 +502,7 @@ nfsdcb(int UNUSED(fd), short which, void *data) - struct idmap_client *ic = data; - struct idmap_msg im; - u_char buf[IDMAP_MAXMSGSZ + 1]; -- size_t len; -+ ssize_t len; - ssize_t bsiz; - char *bp, typebuf[IDMAP_MAXMSGSZ], - buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; -@@ -511,10 +511,14 @@ nfsdcb(int UNUSED(fd), short which, void *data) - if (which != EV_READ) - goto out; - -- if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) { -+ len = read(ic->ic_fd, buf, sizeof(buf)); -+ if (len == 0) -+ /* No upcall to read; not necessarily a problem: */ -+ return; -+ if (len < 0) { - xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)", -- ic->ic_path, len?errno:0, -- len?strerror(errno):"End of File"); -+ ic->ic_path, errno, -+ strerror(errno)); - nfsdreopen_one(ic); - return; - } -diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c -index 6f2ee75..68b9f93 100644 ---- a/utils/mount/configfile.c -+++ b/utils/mount/configfile.c -@@ -73,6 +73,8 @@ struct mnt_alias { - }; - int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); - -+static int strict; -+ - /* - * See if the option is an alias, if so return the - * real mount option along with the argument type. -@@ -286,7 +288,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - char *nvalue, *ptr; - int argtype; - -- list = conf_get_tag_list(section); -+ list = conf_get_tag_list(section, arg); - TAILQ_FOREACH(node, &list->fields, link) { - /* - * Do not overwrite options if already exists -@@ -310,7 +312,15 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - if (strcasecmp(value, "false") == 0) { - if (argtype != MNT_NOARG) - snprintf(buf, BUFSIZ, "no%s", field); -+ else if (strcasecmp(field, "bg") == 0) -+ snprintf(buf, BUFSIZ, "fg"); -+ else if (strcasecmp(field, "fg") == 0) -+ snprintf(buf, BUFSIZ, "bg"); -+ else if (strcasecmp(field, "sloppy") == 0) -+ strict = 1; - } else if (strcasecmp(value, "true") == 0) { -+ if ((strcasecmp(field, "sloppy") == 0) && strict) -+ continue; - snprintf(buf, BUFSIZ, "%s", field); - } else { - nvalue = strdup(value); -@@ -345,6 +355,7 @@ char *conf_get_mntopts(char *spec, char *mount_point, - char *ptr, *server, *config_opts; - int optlen = 0; - -+ strict = 0; - SLIST_INIT(&head); - list_size = 0; - /* -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 4be48cd..e2cdcaf 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -65,11 +65,6 @@ extern int nfs_mount_data_version; - extern char *progname; - extern int verbose; - --static const char *nfs_ns_pgmtbl[] = { -- "status", -- NULL, --}; -- - static const char *nfs_mnt_pgmtbl[] = { - "mount", - "mountd", -@@ -761,18 +756,6 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) - &nfs_server->pmap); - } - --static int nfs_probe_statd(void) --{ -- struct sockaddr_in addr = { -- .sin_family = AF_INET, -- .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -- }; -- rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -- -- return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), -- program, (rpcvers_t)1, IPPROTO_UDP); --} -- - /** - * start_statd - attempt to start rpc.statd - * -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index a8ec46c..2a42b93 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -84,6 +84,20 @@ in - .SS "Options supported by all versions" - These options are valid to use with any NFS version. - .TP 1.5i -+.BI nfsvers= n -+The NFS protocol version number used to contact the server's NFS service. -+If the server does not support the requested version, the mount request -+fails. -+If this option is not specified, the client negotiates a suitable version -+with -+the server, trying version 4 first, version 3 second, and version 2 last. -+.TP 1.5i -+.BI vers= n -+This option is an alternative to the -+.B nfsvers -+option. -+It is included for compatibility with other operating systems -+.TP 1.5i - .BR soft " / " hard - Determines the recovery behavior of the NFS client - after an NFS request times out. -@@ -621,18 +635,6 @@ Using this option ensures that - reports the proper maximum component length to applications - in such cases. - .TP 1.5i --.BI nfsvers= n --The NFS protocol version number used to contact the server's NFS service. --If the server does not support the requested version, the mount request fails. --If this option is not specified, the client negotiates a suitable version with --the server, trying version 4 first, version 3 second, and version 2 last. --.TP 1.5i --.BI vers= n --This option is an alternative to the --.B nfsvers --option. --It is included for compatibility with other operating systems. --.TP 1.5i - .BR lock " / " nolock - Selects whether to use the NLM sideband protocol to lock files on the server. - If neither option is specified (or if -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 737927c..517aa62 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -347,20 +347,26 @@ static char *next_mnt(void **v, char *p) - - static int is_subdirectory(char *child, char *parent) - { -+ /* Check is child is strictly a subdirectory of -+ * parent or a more distant descendant. -+ */ - size_t l = strlen(parent); - -- if (strcmp(parent, "/") == 0) -+ if (strcmp(parent, "/") == 0 && child[1] != 0) - return 1; - -- return strcmp(child, parent) == 0 -- || (strncmp(child, parent, l) == 0 && child[l] == '/'); -+ return (strncmp(child, parent, l) == 0 && child[l] == '/'); - } - - static int path_matches(nfs_export *exp, char *path) - { -- if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -- return is_subdirectory(path, exp->m_export.e_path); -- return strcmp(path, exp->m_export.e_path) == 0; -+ /* Does the path match the export? I.e. is it an -+ * exact match, or does the export have CROSSMOUNT, and path -+ * is a descendant? -+ */ -+ return strcmp(path, exp->m_export.e_path) == 0 -+ || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -+ && is_subdirectory(path, exp->m_export.e_path)); - } - - static int -@@ -369,15 +375,13 @@ export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) - return path_matches(exp, path) && client_matches(exp, dom, ai); - } - --/* True iff e1 is a child of e2 and e2 has crossmnt set: */ -+/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */ - static bool subexport(struct exportent *e1, struct exportent *e2) - { - char *p1 = e1->e_path, *p2 = e2->e_path; -- size_t l2 = strlen(p2); - - return e2->e_flags & NFSEXP_CROSSMOUNT -- && strncmp(p1, p2, l2) == 0 -- && p1[l2] == '/'; -+ && is_subdirectory(p1, p2); - } - - struct parsed_fsid { -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index e87c0a9..6db92f0 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -99,8 +99,8 @@ main(int argc, char **argv) - char *p, *progname, *port; - char *haddr = NULL; - int socket_up = 0; -- int minorvers41 = 0; /* nfsv4 minor version */ -- unsigned int versbits = NFSCTL_ALLBITS; -+ int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */ -+ unsigned int versbits = NFSCTL_VERDEFAULT; - unsigned int protobits = NFSCTL_ALLBITS; - unsigned int proto4 = 0; - unsigned int proto6 = 0; -@@ -160,11 +160,11 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i != 1) { -+ if (i > 2) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- minorvers41 = -1; -+ NFSCTL_VERUNSET(minorvers, i); - break; - } - case 3: -@@ -181,11 +181,11 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i != 1) { -+ if (i > 2) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- minorvers41 = 1; -+ NFSCTL_VERSET(minorvers, i); - break; - } - case 3: -@@ -282,7 +282,7 @@ main(int argc, char **argv) - * registered with rpcbind. Note that on older kernels w/o the right - * interfaces, these are a no-op. - */ -- nfssvc_setvers(versbits, minorvers41); -+ nfssvc_setvers(versbits, minorvers); - - error = nfssvc_set_sockets(AF_INET, proto4, haddr, port); - if (!error) -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 683008e..8b85846 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits, - } - - void --nfssvc_setvers(unsigned int ctlbits, int minorvers41) -+nfssvc_setvers(unsigned int ctlbits, int minorvers) - { - int fd, n, off; - char *ptr; -@@ -280,9 +280,12 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers41) - if (fd < 0) - return; - -- if (minorvers41) -- off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1", -- minorvers41 > 0 ? '+' : '-'); -+ for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { -+ if (NFSCTL_VERISSET(minorvers, n)) -+ off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); -+ else -+ off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); -+ } - for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { - if (NFSCTL_VERISSET(ctlbits, n)) - off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); -diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man -index 47007df..6940788 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.man -+++ b/utils/nfsdcltrack/nfsdcltrack.man -@@ -1,53 +1,3 @@ --.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) --.\" --.\" Standard preamble: --.\" ======================================================================== --.de Sp \" Vertical space (when we can't use .PP) --.if t .sp .5v --.if n .sp --.. --.de Vb \" Begin verbatim text --.ft CW --.nf --.ne \\$1 --.. --.de Ve \" End verbatim text --.ft R --.fi --.. --.\" Set up some character translations and predefined strings. \*(-- will --.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left --.\" double quote, and \*(R" will give a right double quote. \*(C+ will --.\" give a nicer C++. Capital omega is used to do unbreakable dashes and --.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, --.\" nothing in troff, for use with C<>. --.tr \(*W- --.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' --.ie n \{\ --. ds -- \(*W- --. ds PI pi --. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch --. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch --. ds L" "" --. ds R" "" --. ds C` "" --. ds C' "" --'br\} --.el\{\ --. ds -- \|\(em\| --. ds PI \(*p --. ds L" `` --. ds R" '' --'br\} --.\" --.\" Escape single quotes in literal strings from groff's Unicode transform. --.ie \n(.g .ds Aq \(aq --.el .ds Aq ' --.\" --.\" If the F register is turned on, we'll generate index entries on stderr for --.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index --.\" entries marked with X<> in POD. Of course, you'll have to process the --.\" output yourself in some meaningful fashion. - .ie \nF \{\ - . de IX - . tm Index:\\$1\t\\n%\t"\\$2" -@@ -59,70 +9,6 @@ - . de IX - .. - .\} --.\" --.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). --.\" Fear. Run. Save yourself. No user-serviceable parts. --. \" fudge factors for nroff and troff --.if n \{\ --. ds #H 0 --. ds #V .8m --. ds #F .3m --. ds #[ \f1 --. ds #] \fP --.\} --.if t \{\ --. ds #H ((1u-(\\\\n(.fu%2u))*.13m) --. ds #V .6m --. ds #F 0 --. ds #[ \& --. ds #] \& --.\} --. \" simple accents for nroff and troff --.if n \{\ --. ds ' \& --. ds ` \& --. ds ^ \& --. ds , \& --. ds ~ ~ --. ds / --.\} --.if t \{\ --. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" --. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' --. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' --. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' --. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' --. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' --.\} --. \" troff and (daisy-wheel) nroff accents --.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' --.ds 8 \h'\*(#H'\(*b\h'-\*(#H' --.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] --.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' --.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' --.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] --.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] --.ds ae a\h'-(\w'a'u*4/10)'e --.ds Ae A\h'-(\w'A'u*4/10)'E --. \" corrections for vroff --.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' --.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' --. \" for low resolution devices (crt and lpr) --.if \n(.H>23 .if \n(.V>19 \ --\{\ --. ds : e --. ds 8 ss --. ds o a --. ds d- d\h'-1'\(ga --. ds D- D\h'-1'\(hy --. ds th \o'bp' --. ds Th \o'LP' --. ds ae ae --. ds Ae AE --.\} --.rm #[ #] #H #V #F C --.\" ======================================================================== --.\" - .IX Title "NFSDCLTRACK 8" - .TH NFSDCLTRACK 8 "2012-10-24" "" "" - .\" For nroff, turn off justification. Always turn off hyphenation; it makes -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index c0675c4..737a219 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -1,9 +1,10 @@ - ## Process this file with automake to produce Makefile.in - - man8_MANS = nfsidmap.man -- - sbin_PROGRAMS = nfsidmap -+ - nfsidmap_SOURCES = nfsidmap.c - nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -+EXTRA_DIST = id_resolver.conf -diff --git a/utils/nfsidmap/id_resolver.conf b/utils/nfsidmap/id_resolver.conf -new file mode 100644 -index 0000000..2c156c6 ---- /dev/null -+++ b/utils/nfsidmap/id_resolver.conf -@@ -0,0 +1 @@ -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 652546c..8c51bcc 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -28,6 +28,7 @@ - - #include "statd.h" - #include "nfslib.h" -+#include "nfsrpc.h" - #include "nsm.h" - - /* Socket operations */ -@@ -237,6 +238,12 @@ int main (int argc, char **argv) - /* Set hostname */ - MY_NAME = NULL; - -+ /* Refuse to start if another statd is running */ -+ if (nfs_probe_statd()) { -+ fprintf(stderr, "Statd service already running!\n"); -+ exit(1); -+ } -+ - /* Process command line switches */ - while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { - switch (arg) { diff --git a/nfs-utils.1.2.9-rc6.patch b/nfs-utils.1.2.9-rc6.patch deleted file mode 100644 index 998c4b6..0000000 --- a/nfs-utils.1.2.9-rc6.patch +++ /dev/null @@ -1,1597 +0,0 @@ -diff --git a/support/include/conffile.h b/support/include/conffile.h -index ce7aa21..05ea5d2 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -54,7 +54,7 @@ extern int conf_end(int, int); - extern void conf_free_list(struct conf_list *); - extern struct sockaddr *conf_get_address(char *, char *); - extern struct conf_list *conf_get_list(char *, char *); --extern struct conf_list *conf_get_tag_list(char *); -+extern struct conf_list *conf_get_tag_list(char *, char *); - extern int conf_get_num(char *, char *, int); - extern char *conf_get_str(char *, char *); - extern char *conf_get_section(char *, char *, char *); -diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h -index 174c2dd..38db5b5 100644 ---- a/support/include/nfs/nfs.h -+++ b/support/include/nfs/nfs.h -@@ -15,6 +15,10 @@ - #define NFSD_MINVERS 2 - #define NFSD_MAXVERS 4 - -+#define NFS4_MINMINOR 1 -+#define NFS4_MAXMINOR 2 -+#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */ -+ - struct nfs_fh_len { - int fh_size; - u_int8_t fh_handle[NFS3_FHSIZE]; -@@ -52,6 +56,7 @@ struct nfs_fh_old { - #define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) - #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) - -+#define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ - #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) - #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) - #define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index a0b80e1..1bfae7a 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -156,6 +156,11 @@ extern unsigned long nfs_pmap_getport(const struct sockaddr_in *, - const struct timeval *); - - /* -+ * Use nfs_pmap_getport to see if statd is running locally -+ */ -+extern int nfs_probe_statd(void); -+ -+/* - * Contact a remote RPC service to discover whether it is responding - * to requests. - */ -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 5015e94..c3434d5 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -565,7 +565,7 @@ cleanup: - } - - struct conf_list * --conf_get_tag_list(char *section) -+conf_get_tag_list(char *section, char *arg) - { - struct conf_list *list = 0; - struct conf_list_node *node; -@@ -579,6 +579,8 @@ conf_get_tag_list(char *section) - cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); - for (; cb; cb = LIST_NEXT(cb, link)) { - if (strcasecmp (section, cb->section) == 0) { -+ if (arg != NULL && strcasecmp(arg, cb->arg) != 0) -+ continue; - list->cnt++; - node = calloc(1, sizeof *node); - if (!node) -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index dea040f..d3160d3 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -63,6 +63,7 @@ static int parsesquash(char *list, int **idp, int *lenp, char **ep); - static int parsenum(char **cpp); - static void freesquash(void); - static void syntaxerr(char *msg); -+static struct flav_info *find_flavor(char *name); - - void - setexportent(char *fname, char *type) -@@ -196,11 +197,38 @@ getexportent(int fromkernel, int fromexports) - return ⅇ - } - -+static const struct secinfo_flag_displaymap { -+ unsigned int flag; -+ const char *set; -+ const char *unset; -+} secinfo_flag_displaymap[] = { -+ { NFSEXP_READONLY, "ro", "rw" }, -+ { NFSEXP_INSECURE_PORT, "insecure", "secure" }, -+ { NFSEXP_ROOTSQUASH, "root_squash", "no_root_squash" }, -+ { NFSEXP_ALLSQUASH, "all_squash", "no_all_squash" }, -+ { 0, NULL, NULL } -+}; -+ -+static void secinfo_flags_show(FILE *fp, unsigned int flags, unsigned int mask) -+{ -+ const struct secinfo_flag_displaymap *p; -+ -+ for (p = &secinfo_flag_displaymap[0]; p->flag != 0; p++) { -+ if (!(mask & p->flag)) -+ continue; -+ fprintf(fp, ",%s", (flags & p->flag) ? p->set : p->unset); -+ } -+} -+ - void secinfo_show(FILE *fp, struct exportent *ep) - { -+ const struct export_features *ef; - struct sec_entry *p1, *p2; -- int flags; - -+ ef = get_export_features(); -+ -+ if (ep->e_secinfo[0].flav == NULL) -+ secinfo_addflavor(find_flavor("sys"), ep); - for (p1=ep->e_secinfo; p1->flav; p1=p2) { - - fprintf(fp, ",sec=%s", p1->flav->flavour); -@@ -208,12 +236,7 @@ void secinfo_show(FILE *fp, struct exportent *ep) - p2++) { - fprintf(fp, ":%s", p2->flav->flavour); - } -- flags = p1->flags; -- fprintf(fp, ",%s", (flags & NFSEXP_READONLY) ? "ro" : "rw"); -- fprintf(fp, ",%sroot_squash", (flags & NFSEXP_ROOTSQUASH)? -- "" : "no_"); -- fprintf(fp, ",%sall_squash", (flags & NFSEXP_ALLSQUASH)? -- "" : "no_"); -+ secinfo_flags_show(fp, p1->flags, ef->secinfo_flags); - } - } - -@@ -643,8 +666,6 @@ bad_option: - cp++; - } - -- if (ep->e_secinfo[0].flav == NULL) -- secinfo_addflavor(find_flavor("sys"), ep); - fix_pseudoflavor_flags(ep); - ep->e_squids = squids; - ep->e_sqgids = sqgids; -diff --git a/support/nfs/getport.c b/support/nfs/getport.c -index 3331ad4..081594c 100644 ---- a/support/nfs/getport.c -+++ b/support/nfs/getport.c -@@ -1102,3 +1102,25 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, - - return port; - } -+ -+static const char *nfs_ns_pgmtbl[] = { -+ "status", -+ NULL, -+}; -+ -+/* -+ * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally -+ * -+ * Returns non-zero if statd is running locally. -+ */ -+int nfs_probe_statd(void) -+{ -+ struct sockaddr_in addr = { -+ .sin_family = AF_INET, -+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -+ }; -+ rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -+ -+ return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr), -+ program, (rpcvers_t)1, IPPROTO_UDP); -+} -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index b95b71d..3f5fea5 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -53,7 +53,7 @@ class DeviceData: - if words[6].find('nfs') != -1: - self.__nfs_data['statvers'] = words[7] - elif words[0] == 'age:': -- self.__nfs_data['age'] = long(words[1]) -+ self.__nfs_data['age'] = int(words[1]) - elif words[0] == 'opts:': - self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',') - elif words[0] == 'caps:': -@@ -91,12 +91,12 @@ class DeviceData: - self.__nfs_data['shortwrites'] = int(words[22]) - self.__nfs_data['delay'] = int(words[23]) - elif words[0] == 'bytes:': -- self.__nfs_data['normalreadbytes'] = long(words[1]) -- self.__nfs_data['normalwritebytes'] = long(words[2]) -- self.__nfs_data['directreadbytes'] = long(words[3]) -- self.__nfs_data['directwritebytes'] = long(words[4]) -- self.__nfs_data['serverreadbytes'] = long(words[5]) -- self.__nfs_data['serverwritebytes'] = long(words[6]) -+ self.__nfs_data['normalreadbytes'] = int(words[1]) -+ self.__nfs_data['normalwritebytes'] = int(words[2]) -+ self.__nfs_data['directreadbytes'] = int(words[3]) -+ self.__nfs_data['directwritebytes'] = int(words[4]) -+ self.__nfs_data['serverreadbytes'] = int(words[5]) -+ self.__nfs_data['serverwritebytes'] = int(words[6]) - - def __parse_rpc_line(self, words): - if words[0] == 'RPC': -@@ -110,8 +110,8 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[4]) - self.__rpc_data['rpcreceives'] = int(words[5]) - self.__rpc_data['badxids'] = int(words[6]) -- self.__rpc_data['inflightsends'] = long(words[7]) -- self.__rpc_data['backlogutil'] = long(words[8]) -+ self.__rpc_data['inflightsends'] = int(words[7]) -+ self.__rpc_data['backlogutil'] = int(words[8]) - elif words[1] == 'tcp': - self.__rpc_data['port'] = words[2] - self.__rpc_data['bind_count'] = int(words[3]) -@@ -121,7 +121,7 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[7]) - self.__rpc_data['rpcreceives'] = int(words[8]) - self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['inflightsends'] = long(words[10]) -+ self.__rpc_data['inflightsends'] = int(words[10]) - self.__rpc_data['backlogutil'] = int(words[11]) - elif words[1] == 'rdma': - self.__rpc_data['port'] = words[2] -@@ -148,7 +148,7 @@ class DeviceData: - else: - op = words[0][:-1] - self.__rpc_data['ops'] += [op] -- self.__rpc_data[op] = [long(word) for word in words[1:]] -+ self.__rpc_data[op] = [int(word) for word in words[1:]] - - def parse_stats(self, lines): - """Turn a list of lines from a mount stat file into a -@@ -179,81 +179,81 @@ class DeviceData: - def display_nfs_options(self): - """Pretty-print the NFS options - """ -- print 'Stats for %s mounted on %s:' % \ -- (self.__nfs_data['export'], self.__nfs_data['mountpoint']) -- -- print ' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions']) -- print ' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities']) -- if self.__nfs_data.has_key('nfsv4flags'): -- print ' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags']) -- if self.__nfs_data.has_key('pseudoflavor'): -- print ' NFS security flavor: %d pseudoflavor: %d' % \ -- (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor']) -+ print('Stats for %s mounted on %s:' % \ -+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) -+ -+ print(' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])) -+ print(' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])) -+ if 'nfsv4flags' in self.__nfs_data: -+ print(' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags'])) -+ if 'pseudoflavor' in self.__nfs_data: -+ print(' NFS security flavor: %d pseudoflavor: %d' % \ -+ (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor'])) - else: -- print ' NFS security flavor: %d' % self.__nfs_data['flavor'] -+ print(' NFS security flavor: %d' % self.__nfs_data['flavor']) - - def display_nfs_events(self): - """Pretty-print the NFS event counters - """ -- print -- print 'Cache events:' -- print ' data cache invalidated %d times' % self.__nfs_data['datainvalidates'] -- print ' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates'] -- print ' inodes synced %d times' % self.__nfs_data['syncinodes'] -- print -- print 'VFS calls:' -- print ' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates'] -- print ' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates'] -- print -- print ' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir'] -- print ' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup'] -- print ' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission'] -- print ' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen'] -- print ' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush'] -- print ' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock'] -- print ' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync'] -- print ' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease'] -- print -- print 'VM calls:' -- print ' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage'] -- print ' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages'] -- print ' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage'] -- print ' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages'] -- print -- print 'Generic NFS counters:' -- print ' File size changing operations:' -- print ' truncating SETATTRs: %d extending WRITEs: %d' % \ -- (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite']) -- print ' %d silly renames' % self.__nfs_data['sillyrenames'] -- print ' short reads: %d short writes: %d' % \ -- (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites']) -- print ' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay'] -+ print() -+ print('Cache events:') -+ print(' data cache invalidated %d times' % self.__nfs_data['datainvalidates']) -+ print(' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']) -+ print(' inodes synced %d times' % self.__nfs_data['syncinodes']) -+ print() -+ print('VFS calls:') -+ print(' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']) -+ print(' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates']) -+ print() -+ print(' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir']) -+ print(' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup']) -+ print(' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission']) -+ print(' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen']) -+ print(' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush']) -+ print(' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock']) -+ print(' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync']) -+ print(' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease']) -+ print() -+ print('VM calls:') -+ print(' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage']) -+ print(' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages']) -+ print(' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage']) -+ print(' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages']) -+ print() -+ print('Generic NFS counters:') -+ print(' File size changing operations:') -+ print(' truncating SETATTRs: %d extending WRITEs: %d' % \ -+ (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite'])) -+ print(' %d silly renames' % self.__nfs_data['sillyrenames']) -+ print(' short reads: %d short writes: %d' % \ -+ (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])) -+ print(' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']) - - def display_nfs_bytes(self): - """Pretty-print the NFS event counters - """ -- print -- print 'NFS byte counts:' -- print ' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes'] -- print ' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes'] -- print ' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes'] -- print ' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes'] -- print ' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes'] -- print ' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes'] -+ print() -+ print('NFS byte counts:') -+ print(' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes']) -+ print(' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes']) -+ print(' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes']) -+ print(' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes']) -+ print(' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes']) -+ print(' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes']) - - def display_rpc_generic_stats(self): - """Pretty-print the generic RPC stats - """ - sends = self.__rpc_data['rpcsends'] - -- print -- print 'RPC statistics:' -+ print() -+ print('RPC statistics:') - -- print ' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ -- (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids']) -+ print(' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ -+ (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids'])) - if sends != 0: -- print ' average backlog queue length: %d' % \ -- (float(self.__rpc_data['backlogutil']) / sends) -+ print(' average backlog queue length: %d' % \ -+ (float(self.__rpc_data['backlogutil']) / sends)) - - def display_rpc_op_stats(self): - """Pretty-print the per-op stats -@@ -261,23 +261,23 @@ class DeviceData: - sends = self.__rpc_data['rpcsends'] - - # XXX: these should be sorted by 'count' -- print -+ print() - for op in self.__rpc_data['ops']: - stats = self.__rpc_data[op] - count = stats[0] - retrans = stats[1] - count - if count != 0: -- print '%s:' % op -- print '\t%d ops (%d%%)' % \ -- (count, ((count * 100) / sends)), -- print '\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), -- print '\t%d major timeouts' % stats[2] -- print '\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ -- (stats[3] / count, stats[4] / count) -- print '\tbacklog wait: %f' % (float(stats[5]) / count), -- print '\tRTT: %f' % (float(stats[6]) / count), -- print '\ttotal execute time: %f (milliseconds)' % \ -- (float(stats[7]) / count) -+ print('%s:' % op) -+ print('\t%d ops (%d%%)' % \ -+ (count, ((count * 100) / sends)), end=' ') -+ print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') -+ print('\t%d major timeouts' % stats[2]) -+ print('\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ -+ (stats[3] / count, stats[4] / count)) -+ print('\tbacklog wait: %f' % (float(stats[5]) / count), end=' ') -+ print('\tRTT: %f' % (float(stats[6]) / count), end=' ') -+ print('\ttotal execute time: %f (milliseconds)' % \ -+ (float(stats[7]) / count)) - - def compare_iostats(self, old_stats): - """Return the difference between two sets of stats -@@ -285,9 +285,9 @@ class DeviceData: - result = DeviceData() - - # copy self into result -- for key, value in self.__nfs_data.iteritems(): -+ for key, value in self.__nfs_data.items(): - result.__nfs_data[key] = value -- for key, value in self.__rpc_data.iteritems(): -+ for key, value in self.__rpc_data.items(): - result.__rpc_data[key] = value - - # compute the difference of each item in the list -@@ -295,7 +295,7 @@ class DeviceData: - # the reference to them. so we build new lists here - # for the result object. - for op in result.__rpc_data['ops']: -- result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]) -+ result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) - - # update the remaining keys we care about - result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -@@ -312,17 +312,17 @@ class DeviceData: - if sample_time == 0: - sample_time = float(self.__nfs_data['age']) - -- print -- print '%s mounted on %s:' % \ -- (self.__nfs_data['export'], self.__nfs_data['mountpoint']) -+ print() -+ print('%s mounted on %s:' % \ -+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) - -- print '\top/s\trpc bklog' -- print '\t%.2f' % (sends / sample_time), -+ print('\top/s\trpc bklog') -+ print('\t%.2f' % (sends / sample_time), end=' ') - if sends != 0: -- print '\t%.2f' % \ -- ((float(self.__rpc_data['backlogutil']) / sends) / sample_time) -+ print('\t%.2f' % \ -+ ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)) - else: -- print '\t0.00' -+ print('\t0.00') - - # reads: ops/s, kB/s, avg rtt, and avg exe - # XXX: include avg xfer size and retransmits? -@@ -332,15 +332,15 @@ class DeviceData: - rtt = float(read_rpc_stats[6]) - exe = float(read_rpc_stats[7]) - -- print '\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)' -- print '\t\t%.2f' % (ops / sample_time), -- print '\t\t%.2f' % (kilobytes / sample_time), -+ print('\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -+ print('\t\t%.2f' % (ops / sample_time), end=' ') -+ print('\t\t%.2f' % (kilobytes / sample_time), end=' ') - if ops != 0: -- print '\t\t%.2f' % (rtt / ops), -- print '\t\t%.2f' % (exe / ops) -+ print('\t\t%.2f' % (rtt / ops), end=' ') -+ print('\t\t%.2f' % (exe / ops)) - else: -- print '\t\t0.00', -- print '\t\t0.00' -+ print('\t\t0.00', end=' ') -+ print('\t\t0.00') - - # writes: ops/s, kB/s, avg rtt, and avg exe - # XXX: include avg xfer size and retransmits? -@@ -350,15 +350,15 @@ class DeviceData: - rtt = float(write_rpc_stats[6]) - exe = float(write_rpc_stats[7]) - -- print '\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)' -- print '\t\t%.2f' % (ops / sample_time), -- print '\t\t%.2f' % (kilobytes / sample_time), -+ print('\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') -+ print('\t\t%.2f' % (ops / sample_time), end=' ') -+ print('\t\t%.2f' % (kilobytes / sample_time), end=' ') - if ops != 0: -- print '\t\t%.2f' % (rtt / ops), -- print '\t\t%.2f' % (exe / ops) -+ print('\t\t%.2f' % (rtt / ops), end=' ') -+ print('\t\t%.2f' % (exe / ops)) - else: -- print '\t\t0.00', -- print '\t\t0.00' -+ print('\t\t0.00', end=' ') -+ print('\t\t0.00') - - def parse_stats_file(filename): - """pop the contents of a mountstats file into a dictionary, -@@ -388,18 +388,18 @@ def parse_stats_file(filename): - return ms_dict - - def print_mountstats_help(name): -- print 'usage: %s [ options ] ' % name -- print -- print ' Version %s' % Mountstats_version -- print -- print ' Display NFS client per-mount statistics.' -- print -- print ' --version display the version of this command' -- print ' --nfs display only the NFS statistics' -- print ' --rpc display only the RPC statistics' -- print ' --start sample and save statistics' -- print ' --end resample statistics and compare them with saved' -- print -+ print('usage: %s [ options ] ' % name) -+ print() -+ print(' Version %s' % Mountstats_version) -+ print() -+ print(' Display NFS client per-mount statistics.') -+ print() -+ print(' --version display the version of this command') -+ print(' --nfs display only the NFS statistics') -+ print(' --rpc display only the RPC statistics') -+ print(' --start sample and save statistics') -+ print(' --end resample statistics and compare them with saved') -+ print() - - def mountstats_command(): - """Mountstats command -@@ -414,7 +414,7 @@ def mountstats_command(): - return - - if arg in ['-v', '--version', 'version']: -- print '%s version %s' % (sys.argv[0], Mountstats_version) -+ print('%s version %s' % (sys.argv[0], Mountstats_version)) - sys.exit(0) - - if arg in ['-n', '--nfs']: -@@ -426,10 +426,10 @@ def mountstats_command(): - continue - - if arg in ['-s', '--start']: -- raise Exception, 'Sampling is not yet implemented' -+ raise Exception('Sampling is not yet implemented') - - if arg in ['-e', '--end']: -- raise Exception, 'Sampling is not yet implemented' -+ raise Exception('Sampling is not yet implemented') - - if arg == sys.argv[0]: - continue -@@ -448,14 +448,14 @@ def mountstats_command(): - - for mp in mountpoints: - if mp not in mountstats: -- print 'Statistics for mount point %s not found' % mp -+ print('Statistics for mount point %s not found' % mp) - continue - - stats = DeviceData() - stats.parse_stats(mountstats[mp]) - - if not stats.is_nfs_mountpoint(): -- print 'Mount point %s exists but is not an NFS mount' % mp -+ print('Mount point %s exists but is not an NFS mount' % mp) - continue - - if nfs_only: -@@ -472,37 +472,37 @@ def mountstats_command(): - stats.display_rpc_op_stats() - - def print_nfsstat_help(name): -- print 'usage: %s [ options ]' % name -- print -- print ' Version %s' % Mountstats_version -- print -- print ' nfsstat-like program that uses NFS client per-mount statistics.' -- print -+ print('usage: %s [ options ]' % name) -+ print() -+ print(' Version %s' % Mountstats_version) -+ print() -+ print(' nfsstat-like program that uses NFS client per-mount statistics.') -+ print() - - def nfsstat_command(): - print_nfsstat_help(prog) - - def print_iostat_help(name): -- print 'usage: %s [ [ ] ] [ ] ' % name -- print -- print ' Version %s' % Mountstats_version -- print -- print ' iostat-like program to display NFS client per-mount statistics.' -- print -- print ' The parameter specifies the amount of time in seconds between' -- print ' each report. The first report contains statistics for the time since each' -- print ' file system was mounted. Each subsequent report contains statistics' -- print ' collected during the interval since the previous report.' -- print -- print ' If the parameter is specified, the value of determines the' -- print ' number of reports generated at seconds apart. If the interval' -- print ' parameter is specified without the parameter, the command generates' -- print ' reports continuously.' -- print -- print ' If one or more names are specified, statistics for only these' -- print ' mount points will be displayed. Otherwise, all NFS mount points on the' -- print ' client are listed.' -- print -+ print('usage: %s [ [ ] ] [ ] ' % name) -+ print() -+ print(' Version %s' % Mountstats_version) -+ print() -+ print(' iostat-like program to display NFS client per-mount statistics.') -+ print() -+ print(' The parameter specifies the amount of time in seconds between') -+ print(' each report. The first report contains statistics for the time since each') -+ print(' file system was mounted. Each subsequent report contains statistics') -+ print(' collected during the interval since the previous report.') -+ print() -+ print(' If the parameter is specified, the value of determines the') -+ print(' number of reports generated at seconds apart. If the interval') -+ print(' parameter is specified without the parameter, the command generates') -+ print(' reports continuously.') -+ print() -+ print(' If one or more names are specified, statistics for only these') -+ print(' mount points will be displayed. Otherwise, all NFS mount points on the') -+ print(' client are listed.') -+ print() - - def print_iostat_summary(old, new, devices, time): - for device in devices: -@@ -530,7 +530,7 @@ def iostat_command(): - return - - if arg in ['-v', '--version', 'version']: -- print '%s version %s' % (sys.argv[0], Mountstats_version) -+ print('%s version %s' % (sys.argv[0], Mountstats_version)) - return - - if arg == sys.argv[0]: -@@ -543,14 +543,14 @@ def iostat_command(): - if interval > 0: - interval_seen = True - else: -- print 'Illegal value' -+ print('Illegal value') - return - elif not count_seen: - count = int(arg) - if count > 0: - count_seen = True - else: -- print 'Illegal value' -+ print('Illegal value') - return - - # make certain devices contains only NFS mount points -@@ -563,13 +563,13 @@ def iostat_command(): - check += [device] - devices = check - else: -- for device, descr in mountstats.iteritems(): -+ for device, descr in mountstats.items(): - stats = DeviceData() - stats.parse_stats(descr) - if stats.is_nfs_mountpoint(): - devices += [device] - if len(devices) == 0: -- print 'No NFS mount points were found' -+ print('No NFS mount points were found') - return - - old_mountstats = None -@@ -608,7 +608,7 @@ try: - elif prog == 'ms-iostat': - iostat_command() - except KeyboardInterrupt: -- print 'Caught ^C... exiting' -+ print('Caught ^C... exiting') - sys.exit(1) - - sys.exit(0) -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index dfbef87..341cdbf 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -95,7 +95,7 @@ class DeviceData: - if words[6] == 'nfs': - self.__nfs_data['statvers'] = words[7] - elif words[0] == 'age:': -- self.__nfs_data['age'] = long(words[1]) -+ self.__nfs_data['age'] = int(words[1]) - elif words[0] == 'opts:': - self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',') - elif words[0] == 'caps:': -@@ -116,7 +116,7 @@ class DeviceData: - elif words[0] == 'bytes:': - i = 1 - for key in NfsByteCounters: -- self.__nfs_data[key] = long(words[i]) -+ self.__nfs_data[key] = int(words[i]) - i += 1 - - def __parse_rpc_line(self, words): -@@ -131,8 +131,8 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[4]) - self.__rpc_data['rpcreceives'] = int(words[5]) - self.__rpc_data['badxids'] = int(words[6]) -- self.__rpc_data['inflightsends'] = long(words[7]) -- self.__rpc_data['backlogutil'] = long(words[8]) -+ self.__rpc_data['inflightsends'] = int(words[7]) -+ self.__rpc_data['backlogutil'] = int(words[8]) - elif words[1] == 'tcp': - self.__rpc_data['port'] = words[2] - self.__rpc_data['bind_count'] = int(words[3]) -@@ -142,8 +142,8 @@ class DeviceData: - self.__rpc_data['rpcsends'] = int(words[7]) - self.__rpc_data['rpcreceives'] = int(words[8]) - self.__rpc_data['badxids'] = int(words[9]) -- self.__rpc_data['inflightsends'] = long(words[10]) -- self.__rpc_data['backlogutil'] = long(words[11]) -+ self.__rpc_data['inflightsends'] = int(words[10]) -+ self.__rpc_data['backlogutil'] = int(words[11]) - elif words[1] == 'rdma': - self.__rpc_data['port'] = words[2] - self.__rpc_data['bind_count'] = int(words[3]) -@@ -169,7 +169,7 @@ class DeviceData: - else: - op = words[0][:-1] - self.__rpc_data['ops'] += [op] -- self.__rpc_data[op] = [long(word) for word in words[1:]] -+ self.__rpc_data[op] = [int(word) for word in words[1:]] - - def parse_stats(self, lines): - """Turn a list of lines from a mount stat file into a -@@ -271,7 +271,7 @@ class DeviceData: - nfs_stats = self.__nfs_data - lookup_ops = self.__rpc_data['LOOKUP'][0] - readdir_ops = self.__rpc_data['READDIR'][0] -- if self.__rpc_data.has_key('READDIRPLUS'): -+ if 'READDIRPLUS' in self.__rpc_data: - readdir_ops += self.__rpc_data['READDIRPLUS'][0] - - dentry_revals = nfs_stats['dentryrevalidates'] -@@ -330,7 +330,7 @@ class DeviceData: - def __print_rpc_op_stats(self, op, sample_time): - """Print generic stats for one RPC op - """ -- if not self.__rpc_data.has_key(op): -+ if op not in self.__rpc_data: - return - - rpc_stats = self.__rpc_data[op] -@@ -353,14 +353,14 @@ class DeviceData: - exe_per_op = 0.0 - - op += ':' -- print('%s' % op.lower().ljust(15)) -+ print('%s' % op.lower().ljust(15), end='') - print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') - -- print('\t\t%7.3f' % (ops / sample_time)) -- print('\t%7.3f' % (kilobytes / sample_time)) -- print('\t%7.3f' % kb_per_op) -- print(' %7d (%3.1f%%)' % (retrans, retrans_percent)) -- print('\t%7.3f' % rtt_per_op) -+ print('\t\t%7.3f' % (ops / sample_time), end='') -+ print('\t%7.3f' % (kilobytes / sample_time), end='') -+ print('\t%7.3f' % kb_per_op, end='') -+ print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') -+ print('\t%7.3f' % rtt_per_op, end='') - print('\t%7.3f' % exe_per_op) - - def ops(self, sample_time): -@@ -392,7 +392,7 @@ class DeviceData: - print() - - print(' op/s\t\trpc bklog') -- print('%7.2f' % (sends / sample_time)) -+ print('%7.2f' % (sends / sample_time), end='') - print('\t%7.2f' % backlog) - - if which == 0: -@@ -405,7 +405,7 @@ class DeviceData: - elif which == 2: - self.__print_rpc_op_stats('LOOKUP', sample_time) - self.__print_rpc_op_stats('READDIR', sample_time) -- if self.__rpc_data.has_key('READDIRPLUS'): -+ if 'READDIRPLUS' in self.__rpc_data: - self.__print_rpc_op_stats('READDIRPLUS', sample_time) - self.__print_dir_cache_stats(sample_time) - elif which == 3: -@@ -413,6 +413,8 @@ class DeviceData: - self.__print_rpc_op_stats('WRITE', sample_time) - self.__print_page_stats(sample_time) - -+ sys.stdout.flush() -+ - # - # Functions - # -@@ -450,7 +452,7 @@ def print_iostat_summary(old, new, devices, time, options): - if old: - # Trim device list to only include intersection of old and new data, - # this addresses umounts due to autofs mountpoints -- devicelist = filter(lambda x:x in devices,old) -+ devicelist = [x for x in old if x in devices] - else: - devicelist = devices - -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 9f79541..4331697 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -420,7 +420,7 @@ static int test_export(char *path, int with_fsid) - char buf[1024]; - int fd, n; - -- sprintf(buf, "-test-client- %s 3 %d -1 -1 0\n", -+ sprintf(buf, "-test-client- %s 3 %d 65534 65534 0\n", - path, - with_fsid ? NFSEXP_FSID : 0); - fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index bc1de73..58c0f66 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -39,7 +39,7 @@ the export name using a backslash followed by the character code as three - octal digits. - .PP - To apply changes to this file, run --.BR exportfs \-ra -+.BR "exportfs \-ra" - or restart the NFS server. - .PP - .SS Machine Name Formats -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 1df75c5..ac13fd4 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -195,11 +195,28 @@ option when starting - .BR rpc.gssd . - .SH OPTIONS - .TP --.B -D --DNS Reverse lookups are not used for determining the --server names pass to GSSAPI. This option will reverses that and forces --the use of DNS Reverse resolution of the server's IP address to --retrieve the server name to use in GSAPI authentication. -+.B \-D -+The server name passed to GSSAPI for authentication is normally the -+name exactly as requested. e.g. for NFS -+it is the server name in the "servername:/path" mount request. Only if this -+servername appears to be an IP address (IPv4 or IPv6) or an -+unqualified name (no dots) will a reverse DNS lookup -+will be performed to get the canoncial server name. -+ -+If -+.B \-D -+is present, a reverse DNS lookup will -+.I always -+be used, even if the server name looks like a canonical name. So it -+is needed if partially qualified, or non canonical names are regularly -+used. -+ -+Using -+.B \-D -+can introduce a security vulnerability, so it is recommended that -+.B \-D -+not be used, and that canonical names always be used when requesting -+services. - .TP - .B -f - Runs -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index af1844c..e58c341 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -67,7 +67,6 @@ - #include - #include - #include --#include - - #include "gssd.h" - #include "err_util.h" -@@ -176,7 +175,6 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - char *hostname; - char hbuf[NI_MAXHOST]; - unsigned char buf[sizeof(struct in6_addr)]; -- int servername = 0; - - if (avoid_dns) { - /* -@@ -184,15 +182,18 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - * If it is an IP address, do the DNS lookup otherwise - * skip the DNS lookup. - */ -- servername = 0; -- if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1) -- servername = 1; /* IPv4 */ -- else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1) -- servername = 1; /* or IPv6 */ -- -- if (servername) { -+ int is_fqdn = 1; -+ if (strchr(name, '.') == NULL) -+ is_fqdn = 0; /* local name */ -+ else if (inet_pton(AF_INET, name, buf) == 1) -+ is_fqdn = 0; /* IPv4 address */ -+ else if (inet_pton(AF_INET6, name, buf) == 1) -+ is_fqdn = 0; /* IPv6 addrss */ -+ -+ if (is_fqdn) { - return strdup(name); - } -+ /* Sorry, cannot avoid dns after all */ - } - - switch (sa->sa_family) { -@@ -466,8 +467,9 @@ process_clnt_dir(char *dir, char *pdir) - } - sprintf(clp->dirname, "%s/%s", pdir, dir); - if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) { -- printerr(0, "ERROR: can't open %s: %s\n", -- clp->dirname, strerror(errno)); -+ if (errno != ENOENT) -+ printerr(0, "ERROR: can't open %s: %s\n", -+ clp->dirname, strerror(errno)); - goto fail_destroy_client; - } - fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL); -@@ -523,7 +525,7 @@ update_old_clients(struct dirent **namelist, int size, char *pdir) - /* only compare entries in the global list that are from the - * same pipefs parent directory as "pdir" - */ -- if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue; -+ if (strcmp(clp->dirname, pdir) != 0) continue; - - stillhere = 0; - for (i=0; i < size; i++) { -@@ -820,6 +822,7 @@ set_port: - */ - static int - create_auth_rpc_client(struct clnt_info *clp, -+ char *tgtname, - CLIENT **clnt_return, - AUTH **auth_return, - uid_t uid, -@@ -924,14 +927,16 @@ create_auth_rpc_client(struct clnt_info *clp, - clnt_spcreateerror(rpc_errmsg)); - goto out_fail; - } -+ if (!tgtname) -+ tgtname = clp->servicename; - -- printerr(2, "creating context with server %s\n", clp->servicename); -- auth = authgss_create_default(rpc_clnt, clp->servicename, &sec); -+ printerr(2, "creating context with server %s\n", tgtname); -+ 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 " - "user with uid %d for server %s\n", -- uid, clp->servername); -+ uid, tgtname); - goto out_fail; - } - -@@ -1013,7 +1018,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - /* Try first to acquire credentials directly via GSSAPI */ - err = gssd_acquire_user_cred(uid, &gss_cred); - if (!err) -- create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, -+ create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, - AUTHTYPE_KRB5, gss_cred); - /* if create_auth_rplc_client fails try the traditional method of - * trolling for credentials */ -@@ -1022,7 +1027,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - if (err == -EKEYEXPIRED) - downcall_err = -EKEYEXPIRED; - else if (!err) -- create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, -+ create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, - AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL); - } - } -@@ -1033,8 +1038,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - int success = 0; - do { - gssd_refresh_krb5_machine_credential(clp->servername, -- NULL, service, -- tgtname); -+ NULL, service); - /* - * Get a list of credential cache names and try each - * of them until one works or we've tried them all -@@ -1047,7 +1051,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - } - for (ccname = credlist; ccname && *ccname; ccname++) { - gssd_setup_krb5_machine_gss_ccache(*ccname); -- if ((create_auth_rpc_client(clp, &rpc_clnt, -+ if ((create_auth_rpc_client(clp, tgtname, &rpc_clnt, - &auth, uid, - AUTHTYPE_KRB5, - GSS_C_NO_CREDENTIAL)) == 0) { -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 6275dd8..c6e52fd 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -231,7 +231,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, - continue; - } - if (uid == 0 && !root_uses_machine_creds && -- strstr(namelist[i]->d_name, "_machine_")) { -+ strstr(namelist[i]->d_name, "machine_")) { - printerr(3, "CC '%s' not available to root\n", - statname); - free(namelist[i]); -@@ -825,8 +825,10 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - - retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) -- goto out; -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - - code = krb5_get_default_realm(context, &default_realm); - if (code) { -@@ -852,11 +854,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - } - - /* -- * Try the "appropriate" realm first, and if nothing found for that -- * realm, try the default realm (if it hasn't already been tried). -+ * Make sure the preferred_realm, which may have been explicitly set -+ * on the command line, is tried first. If nothing is found go on with -+ * the host and local default realm (if that hasn't already been tried). - */ - i = 0; - realm = realmnames[i]; -+ -+ if (strcmp (realm, preferred_realm) != 0) { -+ realm = preferred_realm; -+ /* resetting the realmnames index */ -+ i = -1; -+ } -+ - while (1) { - if (realm == NULL) { - tried_all = 1; -@@ -883,6 +893,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad, - NULL); - } else { -+ if (!myhostname[0]) -+ continue; - snprintf(spn, sizeof(spn), "%s/%s@%s", - svcnames[j], myhostname, realm); - code = krb5_build_principal_ext(context, &princ, -@@ -1137,7 +1149,7 @@ gssd_get_krb5_machine_cred_list(char ***list) - if (ple->ccname) { - /* Make sure cred is up-to-date before returning it */ - retval = gssd_refresh_krb5_machine_credential(NULL, ple, -- NULL, NULL); -+ NULL); - if (retval) - continue; - if (i + 1 > listsize) { -@@ -1228,15 +1240,14 @@ gssd_destroy_krb5_machine_creds(void) - int - gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service, -- char *tgtname) -+ char *service) - { - krb5_error_code code = 0; - krb5_context context; - krb5_keytab kt = NULL;; - int retval = 0; - char *k5err = NULL; -- const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; -+ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - - /* - * If a specific service name was specified, use it. -@@ -1268,10 +1279,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, - if (ple == NULL) { - krb5_keytab_entry kte; - -- if (tgtname == NULL) -- tgtname = hostname; -- -- code = find_keytab_entry(context, kt, tgtname, &kte, svcnames); -+ code = find_keytab_entry(context, kt, hostname, &kte, svcnames); - if (code) { - printerr(0, "ERROR: %s: no usable keytab entry found " - "in keytab %s for connection with host %s\n", -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index eed1294..3f0723e 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -31,8 +31,7 @@ void gssd_setup_krb5_machine_gss_ccache(char *servername); - void gssd_destroy_krb5_machine_creds(void); - int gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service, -- char *tgtname); -+ char *service); - char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); - void gssd_k5_get_default_realm(char **def_realm); - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index beba9c4..b6c6231 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -502,7 +502,7 @@ nfsdcb(int UNUSED(fd), short which, void *data) - struct idmap_client *ic = data; - struct idmap_msg im; - u_char buf[IDMAP_MAXMSGSZ + 1]; -- size_t len; -+ ssize_t len; - ssize_t bsiz; - char *bp, typebuf[IDMAP_MAXMSGSZ], - buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; -@@ -511,10 +511,14 @@ nfsdcb(int UNUSED(fd), short which, void *data) - if (which != EV_READ) - goto out; - -- if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) { -+ len = read(ic->ic_fd, buf, sizeof(buf)); -+ if (len == 0) -+ /* No upcall to read; not necessarily a problem: */ -+ return; -+ if (len < 0) { - xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)", -- ic->ic_path, len?errno:0, -- len?strerror(errno):"End of File"); -+ ic->ic_path, errno, -+ strerror(errno)); - nfsdreopen_one(ic); - return; - } -diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c -index 6f2ee75..68b9f93 100644 ---- a/utils/mount/configfile.c -+++ b/utils/mount/configfile.c -@@ -73,6 +73,8 @@ struct mnt_alias { - }; - int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); - -+static int strict; -+ - /* - * See if the option is an alias, if so return the - * real mount option along with the argument type. -@@ -286,7 +288,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - char *nvalue, *ptr; - int argtype; - -- list = conf_get_tag_list(section); -+ list = conf_get_tag_list(section, arg); - TAILQ_FOREACH(node, &list->fields, link) { - /* - * Do not overwrite options if already exists -@@ -310,7 +312,15 @@ conf_parse_mntopts(char *section, char *arg, char *opts) - if (strcasecmp(value, "false") == 0) { - if (argtype != MNT_NOARG) - snprintf(buf, BUFSIZ, "no%s", field); -+ else if (strcasecmp(field, "bg") == 0) -+ snprintf(buf, BUFSIZ, "fg"); -+ else if (strcasecmp(field, "fg") == 0) -+ snprintf(buf, BUFSIZ, "bg"); -+ else if (strcasecmp(field, "sloppy") == 0) -+ strict = 1; - } else if (strcasecmp(value, "true") == 0) { -+ if ((strcasecmp(field, "sloppy") == 0) && strict) -+ continue; - snprintf(buf, BUFSIZ, "%s", field); - } else { - nvalue = strdup(value); -@@ -345,6 +355,7 @@ char *conf_get_mntopts(char *spec, char *mount_point, - char *ptr, *server, *config_opts; - int optlen = 0; - -+ strict = 0; - SLIST_INIT(&head); - list_size = 0; - /* -diff --git a/utils/mount/network.c b/utils/mount/network.c -index 4be48cd..e2cdcaf 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -65,11 +65,6 @@ extern int nfs_mount_data_version; - extern char *progname; - extern int verbose; - --static const char *nfs_ns_pgmtbl[] = { -- "status", -- NULL, --}; -- - static const char *nfs_mnt_pgmtbl[] = { - "mount", - "mountd", -@@ -761,18 +756,6 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) - &nfs_server->pmap); - } - --static int nfs_probe_statd(void) --{ -- struct sockaddr_in addr = { -- .sin_family = AF_INET, -- .sin_addr.s_addr = htonl(INADDR_LOOPBACK), -- }; -- rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); -- -- return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), -- program, (rpcvers_t)1, IPPROTO_UDP); --} -- - /** - * start_statd - attempt to start rpc.statd - * -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index a8ec46c..2a42b93 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -84,6 +84,20 @@ in - .SS "Options supported by all versions" - These options are valid to use with any NFS version. - .TP 1.5i -+.BI nfsvers= n -+The NFS protocol version number used to contact the server's NFS service. -+If the server does not support the requested version, the mount request -+fails. -+If this option is not specified, the client negotiates a suitable version -+with -+the server, trying version 4 first, version 3 second, and version 2 last. -+.TP 1.5i -+.BI vers= n -+This option is an alternative to the -+.B nfsvers -+option. -+It is included for compatibility with other operating systems -+.TP 1.5i - .BR soft " / " hard - Determines the recovery behavior of the NFS client - after an NFS request times out. -@@ -621,18 +635,6 @@ Using this option ensures that - reports the proper maximum component length to applications - in such cases. - .TP 1.5i --.BI nfsvers= n --The NFS protocol version number used to contact the server's NFS service. --If the server does not support the requested version, the mount request fails. --If this option is not specified, the client negotiates a suitable version with --the server, trying version 4 first, version 3 second, and version 2 last. --.TP 1.5i --.BI vers= n --This option is an alternative to the --.B nfsvers --option. --It is included for compatibility with other operating systems. --.TP 1.5i - .BR lock " / " nolock - Selects whether to use the NLM sideband protocol to lock files on the server. - If neither option is specified (or if -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 737927c..517aa62 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -347,20 +347,26 @@ static char *next_mnt(void **v, char *p) - - static int is_subdirectory(char *child, char *parent) - { -+ /* Check is child is strictly a subdirectory of -+ * parent or a more distant descendant. -+ */ - size_t l = strlen(parent); - -- if (strcmp(parent, "/") == 0) -+ if (strcmp(parent, "/") == 0 && child[1] != 0) - return 1; - -- return strcmp(child, parent) == 0 -- || (strncmp(child, parent, l) == 0 && child[l] == '/'); -+ return (strncmp(child, parent, l) == 0 && child[l] == '/'); - } - - static int path_matches(nfs_export *exp, char *path) - { -- if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -- return is_subdirectory(path, exp->m_export.e_path); -- return strcmp(path, exp->m_export.e_path) == 0; -+ /* Does the path match the export? I.e. is it an -+ * exact match, or does the export have CROSSMOUNT, and path -+ * is a descendant? -+ */ -+ return strcmp(path, exp->m_export.e_path) == 0 -+ || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) -+ && is_subdirectory(path, exp->m_export.e_path)); - } - - static int -@@ -369,15 +375,13 @@ export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) - return path_matches(exp, path) && client_matches(exp, dom, ai); - } - --/* True iff e1 is a child of e2 and e2 has crossmnt set: */ -+/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */ - static bool subexport(struct exportent *e1, struct exportent *e2) - { - char *p1 = e1->e_path, *p2 = e2->e_path; -- size_t l2 = strlen(p2); - - return e2->e_flags & NFSEXP_CROSSMOUNT -- && strncmp(p1, p2, l2) == 0 -- && p1[l2] == '/'; -+ && is_subdirectory(p1, p2); - } - - struct parsed_fsid { -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index e87c0a9..6db92f0 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -99,8 +99,8 @@ main(int argc, char **argv) - char *p, *progname, *port; - char *haddr = NULL; - int socket_up = 0; -- int minorvers41 = 0; /* nfsv4 minor version */ -- unsigned int versbits = NFSCTL_ALLBITS; -+ int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */ -+ unsigned int versbits = NFSCTL_VERDEFAULT; - unsigned int protobits = NFSCTL_ALLBITS; - unsigned int proto4 = 0; - unsigned int proto6 = 0; -@@ -160,11 +160,11 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i != 1) { -+ if (i > 2) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- minorvers41 = -1; -+ NFSCTL_VERUNSET(minorvers, i); - break; - } - case 3: -@@ -181,11 +181,11 @@ main(int argc, char **argv) - case 4: - if (*p == '.') { - int i = atoi(p+1); -- if (i != 1) { -+ if (i > 2) { - fprintf(stderr, "%s: unsupported minor version\n", optarg); - exit(1); - } -- minorvers41 = 1; -+ NFSCTL_VERSET(minorvers, i); - break; - } - case 3: -@@ -282,7 +282,7 @@ main(int argc, char **argv) - * registered with rpcbind. Note that on older kernels w/o the right - * interfaces, these are a no-op. - */ -- nfssvc_setvers(versbits, minorvers41); -+ nfssvc_setvers(versbits, minorvers); - - error = nfssvc_set_sockets(AF_INET, proto4, haddr, port); - if (!error) -diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c -index 683008e..8b85846 100644 ---- a/utils/nfsd/nfssvc.c -+++ b/utils/nfsd/nfssvc.c -@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits, - } - - void --nfssvc_setvers(unsigned int ctlbits, int minorvers41) -+nfssvc_setvers(unsigned int ctlbits, int minorvers) - { - int fd, n, off; - char *ptr; -@@ -280,9 +280,12 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers41) - if (fd < 0) - return; - -- if (minorvers41) -- off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1", -- minorvers41 > 0 ? '+' : '-'); -+ for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { -+ if (NFSCTL_VERISSET(minorvers, n)) -+ off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); -+ else -+ off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); -+ } - for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { - if (NFSCTL_VERISSET(ctlbits, n)) - off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); -diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man -index 47007df..6940788 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.man -+++ b/utils/nfsdcltrack/nfsdcltrack.man -@@ -1,53 +1,3 @@ --.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) --.\" --.\" Standard preamble: --.\" ======================================================================== --.de Sp \" Vertical space (when we can't use .PP) --.if t .sp .5v --.if n .sp --.. --.de Vb \" Begin verbatim text --.ft CW --.nf --.ne \\$1 --.. --.de Ve \" End verbatim text --.ft R --.fi --.. --.\" Set up some character translations and predefined strings. \*(-- will --.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left --.\" double quote, and \*(R" will give a right double quote. \*(C+ will --.\" give a nicer C++. Capital omega is used to do unbreakable dashes and --.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, --.\" nothing in troff, for use with C<>. --.tr \(*W- --.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' --.ie n \{\ --. ds -- \(*W- --. ds PI pi --. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch --. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch --. ds L" "" --. ds R" "" --. ds C` "" --. ds C' "" --'br\} --.el\{\ --. ds -- \|\(em\| --. ds PI \(*p --. ds L" `` --. ds R" '' --'br\} --.\" --.\" Escape single quotes in literal strings from groff's Unicode transform. --.ie \n(.g .ds Aq \(aq --.el .ds Aq ' --.\" --.\" If the F register is turned on, we'll generate index entries on stderr for --.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index --.\" entries marked with X<> in POD. Of course, you'll have to process the --.\" output yourself in some meaningful fashion. - .ie \nF \{\ - . de IX - . tm Index:\\$1\t\\n%\t"\\$2" -@@ -59,70 +9,6 @@ - . de IX - .. - .\} --.\" --.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). --.\" Fear. Run. Save yourself. No user-serviceable parts. --. \" fudge factors for nroff and troff --.if n \{\ --. ds #H 0 --. ds #V .8m --. ds #F .3m --. ds #[ \f1 --. ds #] \fP --.\} --.if t \{\ --. ds #H ((1u-(\\\\n(.fu%2u))*.13m) --. ds #V .6m --. ds #F 0 --. ds #[ \& --. ds #] \& --.\} --. \" simple accents for nroff and troff --.if n \{\ --. ds ' \& --. ds ` \& --. ds ^ \& --. ds , \& --. ds ~ ~ --. ds / --.\} --.if t \{\ --. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" --. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' --. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' --. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' --. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' --. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' --.\} --. \" troff and (daisy-wheel) nroff accents --.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' --.ds 8 \h'\*(#H'\(*b\h'-\*(#H' --.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] --.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' --.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' --.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] --.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] --.ds ae a\h'-(\w'a'u*4/10)'e --.ds Ae A\h'-(\w'A'u*4/10)'E --. \" corrections for vroff --.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' --.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' --. \" for low resolution devices (crt and lpr) --.if \n(.H>23 .if \n(.V>19 \ --\{\ --. ds : e --. ds 8 ss --. ds o a --. ds d- d\h'-1'\(ga --. ds D- D\h'-1'\(hy --. ds th \o'bp' --. ds Th \o'LP' --. ds ae ae --. ds Ae AE --.\} --.rm #[ #] #H #V #F C --.\" ======================================================================== --.\" - .IX Title "NFSDCLTRACK 8" - .TH NFSDCLTRACK 8 "2012-10-24" "" "" - .\" For nroff, turn off justification. Always turn off hyphenation; it makes -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index c0675c4..737a219 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -1,9 +1,10 @@ - ## Process this file with automake to produce Makefile.in - - man8_MANS = nfsidmap.man -- - sbin_PROGRAMS = nfsidmap -+ - nfsidmap_SOURCES = nfsidmap.c - nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -+EXTRA_DIST = id_resolver.conf -diff --git a/utils/nfsidmap/id_resolver.conf b/utils/nfsidmap/id_resolver.conf -new file mode 100644 -index 0000000..2c156c6 ---- /dev/null -+++ b/utils/nfsidmap/id_resolver.conf -@@ -0,0 +1 @@ -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 652546c..8c51bcc 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -28,6 +28,7 @@ - - #include "statd.h" - #include "nfslib.h" -+#include "nfsrpc.h" - #include "nsm.h" - - /* Socket operations */ -@@ -237,6 +238,12 @@ int main (int argc, char **argv) - /* Set hostname */ - MY_NAME = NULL; - -+ /* Refuse to start if another statd is running */ -+ if (nfs_probe_statd()) { -+ fprintf(stderr, "Statd service already running!\n"); -+ exit(1); -+ } -+ - /* Process command line switches */ - while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { - switch (arg) { diff --git a/nfs-utils.spec b/nfs-utils.spec index ec66380..06258d3 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.2 -Release: 0.2%{?dist} +Release: 1.0%{?dist} Epoch: 1 # group all 32bit related archs @@ -15,8 +15,7 @@ Source2: nfs.sysconfig Source3: nfs-utils_env.sh Source4: lockd.conf -Patch001: nfs-utils-1.3.2-statd-bg.patch -Patch002: nfs-utils-1.3.2-statd-nowait.patch +Patch001: nfs-utils-1.3.3-rc1.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -74,7 +73,6 @@ This package also contains the mount.nfs and umount.nfs program. %setup -q %patch001 -p1 -%patch002 -p1 %patch100 -p1 %patch101 -p1 @@ -307,6 +305,9 @@ fi /sbin/umount.nfs4 %changelog +* Thu Feb 26 2015 Steve Dickson 1.3.2-1.0 +- Update to latest RC release: nfs-utils-1-3-3-rc1 + * Mon Feb 9 2015 Steve Dickson 1.3.2-0.2 - Change statd-notify.service to not wait for network to come up (bz 1183293) - Added the rpcuser group before adding the rpcuser uid (bz 1165322) diff --git a/sources b/sources index 05716c6..0660fa8 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -8de676b9ff34b8f9addc1d0800fabdf8 nfs-utils-1.3.1.tar.xz 4cdffb2c7f7fd2bdceaba55ab1b881da nfs-utils-1.3.2.tar.xz