diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e01d01 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/nfs-utils-1.3.0.tar.xz diff --git a/.nfs-utils.metadata b/.nfs-utils.metadata new file mode 100644 index 0000000..1f0682f --- /dev/null +++ b/.nfs-utils.metadata @@ -0,0 +1 @@ +c4308c2560748c35467483ca98ce050bd985f1fa SOURCES/nfs-utils-1.3.0.tar.xz diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/24-nfs-server.conf b/SOURCES/24-nfs-server.conf new file mode 100644 index 0000000..5011e92 --- /dev/null +++ b/SOURCES/24-nfs-server.conf @@ -0,0 +1,7 @@ +[service/nfs-server] + mechs = krb5 + socket = /run/gssproxy.sock + cred_store = keytab:/etc/krb5.keytab + trusted = yes + kernel_nfsd = yes + euid = 0 diff --git a/SOURCES/id_resolver.conf b/SOURCES/id_resolver.conf new file mode 100644 index 0000000..67ccb18 --- /dev/null +++ b/SOURCES/id_resolver.conf @@ -0,0 +1,9 @@ +# +# nfsidmap(5) - The NFS idmapper upcall program +# Summary: Used by NFSv4 to map user/group ids into +# user/group names and names into in ids +# Options: +# -v Increases the verbosity of the output to syslog +# -t timeout Set the expiration timer, in seconds, on the key +# +create id_resolver * * /usr/sbin/nfsidmap %k %d diff --git a/SOURCES/lockd.conf b/SOURCES/lockd.conf new file mode 100644 index 0000000..759f31d --- /dev/null +++ b/SOURCES/lockd.conf @@ -0,0 +1,22 @@ +# +# Set the NFS lock manager grace period. n is measured in seconds. +#options lockd nlm_grace_period=90 +# +# Set the TCP port that the NFS lock manager should use. +# port must be a valid TCP port value (1-65535). +#options lockd nlm_tcpport +# +# Set the UDP port that the NFS lock manager should use. +# port must be a valid UDP port value (1-65535). +#options lockd nlm_udpport +# +# Set the maximum number of outstanding connections +#options lockd nlm_max_connections=1024 +# +# Set the default time value for the NFS lock manager +# in seconds. Default is 10 secs (min 3 max 20) +#options lockd nlm_timeout=10 +# +# Choose whether to record the caller_name or IP address +# this peer in the local rpc.statd's database. +#options lockd nsm_use_hostnames=0 diff --git a/SOURCES/nfs-utils-1.2.1-exp-subtree-warn-off.patch b/SOURCES/nfs-utils-1.2.1-exp-subtree-warn-off.patch new file mode 100644 index 0000000..0ee49bd --- /dev/null +++ b/SOURCES/nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/support/nfs/exports.c.orig nfs-utils-1.3.0/support/nfs/exports.c +--- nfs-utils-1.3.0/support/nfs/exports.c.orig 2017-04-27 14:09:49.090353525 -0400 ++++ nfs-utils-1.3.0/support/nfs/exports.c 2017-04-27 14:10:09.083034672 -0400 +@@ -507,7 +507,7 @@ void fix_pseudoflavor_flags(struct expor + static int + parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr) + { +- int had_subtree_opt = 0; ++ int had_subtree_opt = 1; + char *flname = efname?efname:"command line"; + int flline = efp?efp->x_line:0; + unsigned int active = 0; diff --git a/SOURCES/nfs-utils-1.2.1-statdpath-man.patch b/SOURCES/nfs-utils-1.2.1-statdpath-man.patch new file mode 100644 index 0000000..53e2f34 --- /dev/null +++ b/SOURCES/nfs-utils-1.2.1-statdpath-man.patch @@ -0,0 +1,58 @@ +diff -up nfs-utils-1.3.0/utils/statd/sm-notify.man.orig nfs-utils-1.3.0/utils/statd/sm-notify.man +--- nfs-utils-1.3.0/utils/statd/sm-notify.man.orig 2017-04-27 14:08:24.681720773 -0400 ++++ nfs-utils-1.3.0/utils/statd/sm-notify.man 2017-04-27 14:09:05.347042274 -0400 +@@ -184,7 +184,7 @@ where NSM state information resides. + If this option is not specified, + .B sm-notify + uses +-.I /var/lib/nfs ++.I /var/lib/nfs/statd + by default. + .IP + After starting, +@@ -330,13 +330,13 @@ Currently, the + command supports sending notification only via datagram transport protocols. + .SH FILES + .TP 2.5i +-.I /var/lib/nfs/sm ++.I /var/lib/nfs/statd/sm + directory containing monitor list + .TP 2.5i +-.I /var/lib/nfs/sm.bak ++.I /var/lib/nfs/statd/sm.bak + directory containing notify list + .TP 2.5i +-.I /var/lib/nfs/state ++.I /var/lib/nfs/statd/state + NSM state number for this host + .TP 2.5i + .I /proc/sys/fs/nfs/nsm_local_state +diff -up nfs-utils-1.3.0/utils/statd/statd.man.orig nfs-utils-1.3.0/utils/statd/statd.man +--- nfs-utils-1.3.0/utils/statd/statd.man.orig 2017-04-27 14:08:24.662721095 -0400 ++++ nfs-utils-1.3.0/utils/statd/statd.man 2017-04-27 14:09:05.347042274 -0400 +@@ -253,7 +253,7 @@ where NSM state information resides. + If this option is not specified, + .B rpc.statd + uses +-.I /var/lib/nfs ++.I /var/lib/nfs/statd + by default. + .IP + After starting, +@@ -425,13 +425,13 @@ If set to a positive integer, has the sa + .IR \-\-no\-notify . + .SH FILES + .TP 2.5i +-.I /var/lib/nfs/sm ++.I /var/lib/nfs/statd/sm + directory containing monitor list + .TP 2.5i +-.I /var/lib/nfs/sm.bak ++.I /var/lib/nfs/statd/sm.bak + directory containing notify list + .TP 2.5i +-.I /var/lib/nfs/state ++.I /var/lib/nfs/statd/state + NSM state number for this host + .TP 2.5i + .I /var/run/run.statd.pid diff --git a/SOURCES/nfs-utils-1.2.3-sm-notify-res_init.patch b/SOURCES/nfs-utils-1.2.3-sm-notify-res_init.patch new file mode 100644 index 0000000..7b1ea1d --- /dev/null +++ b/SOURCES/nfs-utils-1.2.3-sm-notify-res_init.patch @@ -0,0 +1,21 @@ +diff -up nfs-utils-1.3.0/utils/statd/sm-notify.c.orig nfs-utils-1.3.0/utils/statd/sm-notify.c +--- nfs-utils-1.3.0/utils/statd/sm-notify.c.orig 2017-04-27 14:10:28.866713955 -0400 ++++ nfs-utils-1.3.0/utils/statd/sm-notify.c 2017-04-27 14:10:50.454363993 -0400 +@@ -28,6 +28,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "conffile.h" + #include "sockaddr.h" +@@ -91,6 +94,7 @@ smn_lookup(const char *name) + }; + int error; + ++ res_init(); + error = getaddrinfo(name, NULL, &hint, &ai); + if (error != 0) { + xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error)); diff --git a/SOURCES/nfs-utils-1.2.5-idmap-errmsg.patch b/SOURCES/nfs-utils-1.2.5-idmap-errmsg.patch new file mode 100644 index 0000000..99e16b1 --- /dev/null +++ b/SOURCES/nfs-utils-1.2.5-idmap-errmsg.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c.orig nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c +--- nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c.orig 2017-04-27 14:11:05.788115492 -0400 ++++ nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c 2017-04-27 14:11:26.291788824 -0400 +@@ -417,7 +417,7 @@ int main(int argc, char **argv) + + xlog_stderr(verbose); + if ((argc - optind) != 2) { +- xlog_warn("Bad arg count. Check /etc/request-key.conf"); ++ xlog_warn("Bad arg count. Check /etc/request-key.d/request-key.conf"); + xlog_warn(usage, progname); + return EXIT_FAILURE; + } diff --git a/SOURCES/nfs-utils-1.2.9-exportfs-badentries.patch b/SOURCES/nfs-utils-1.2.9-exportfs-badentries.patch new file mode 100644 index 0000000..897a96f --- /dev/null +++ b/SOURCES/nfs-utils-1.2.9-exportfs-badentries.patch @@ -0,0 +1,94 @@ +diff --git a/support/export/client.c b/support/export/client.c +index dbf47b9..0f7b4fe 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..ce714d4 100644 +--- a/support/export/export.c ++++ b/support/export/export.c +@@ -76,15 +76,22 @@ 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) { ++ exp = export_create(eep, 0); ++ if (exp) ++ volumes++; ++ } + else + warn_duplicated_exports(exp, eep); + } + endexportent(); ++ if (volumes == 0) ++ xlog(L_ERROR, "No file systems exported!"); + } + + /** +diff --git a/support/export/hostname.c b/support/export/hostname.c +index 5f31aee..cdf9e76 100644 +--- a/support/export/hostname.c ++++ b/support/export/hostname.c +@@ -137,11 +137,11 @@ host_pton(const char *paddr) + case EAI_NONAME: + break; + case EAI_SYSTEM: +- xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", ++ xlog(L_WARNING, "%s: failed to convert %s: (%d) %m", + __func__, paddr, errno); + break; + default: +- xlog(D_GENERAL, "%s: failed to convert %s: %s", ++ xlog(L_WARNING, "%s: failed to convert %s: %s", + __func__, paddr, gai_strerror(error)); + break; + } +@@ -179,11 +179,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/systemd/nfs-server.service b/systemd/nfs-server.service +index f0e456a..7f60f39 100644 +--- a/systemd/nfs-server.service ++++ b/systemd/nfs-server.service +@@ -23,13 +23,13 @@ EnvironmentFile=-/run/sysconfig/nfs-utils + + Type=oneshot + RemainAfterExit=yes +-ExecStartPre=/usr/sbin/exportfs -r ++ExecStartPre=-/usr/sbin/exportfs -r + ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS + ExecStop=/usr/sbin/rpc.nfsd 0 + ExecStopPost=/usr/sbin/exportfs -au + ExecStopPost=/usr/sbin/exportfs -f + +-ExecReload=/usr/sbin/exportfs -r ++ExecReload=-/usr/sbin/exportfs -r + + [Install] + WantedBy=multi-user.target diff --git a/SOURCES/nfs-utils-1.3.0-blkmapd-loop.patch b/SOURCES/nfs-utils-1.3.0-blkmapd-loop.patch new file mode 100644 index 0000000..b8ca230 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-blkmapd-loop.patch @@ -0,0 +1,35 @@ +commit c6b8191374d9ad064eb96423400a6314c2d0102e +Author: Kinglong Mee +Date: Tue Jun 30 14:12:38 2015 -0400 + + blkmapd: Fix infinite loop when reading serial + + If (dev_id->ids & 0xf) < current_id, must updates pos when continue. + Otherwise an infinite loop. + + No other places use the pos value, just move to the top of while. + + Signed-off-by: Kinglong Mee + Signed-off-by: Steve Dickson + +diff --git a/utils/blkmapd/device-inq.c b/utils/blkmapd/device-inq.c +index c5bf71f..6b56b67 100644 +--- a/utils/blkmapd/device-inq.c ++++ b/utils/blkmapd/device-inq.c +@@ -196,6 +196,8 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + + while (pos < (len - devid_len)) { + dev_id = (struct bl_dev_id *)&(dev_root->data[pos]); ++ pos += (dev_id->len + devid_len); ++ + if ((dev_id->ids & 0xf) < current_id) + continue; + switch (dev_id->ids & 0xf) { +@@ -226,7 +228,6 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + } + if (current_id == 3) + break; +- pos += (dev_id->len + devid_len); + } + out: + if (!serial_out) diff --git a/SOURCES/nfs-utils-1.3.0-blkmapd-pnfs.patch b/SOURCES/nfs-utils-1.3.0-blkmapd-pnfs.patch new file mode 100644 index 0000000..e1c8e3e --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-blkmapd-pnfs.patch @@ -0,0 +1,354 @@ +diff --git a/Makefile.am b/Makefile.am +index ae7cd16..c9e9f87 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2,7 +2,7 @@ + + AUTOMAKE_OPTIONS = foreign + +-SUBDIRS = tools support utils linux-nfs tests ++SUBDIRS = tools support utils linux-nfs tests systemd + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/configure.ac b/configure.ac +index 7b93de6..4ee4db5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -54,6 +54,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@:>@])], +@@ -506,6 +516,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/include/nfs/export.h b/support/include/nfs/export.h +index 2f59e6a..1194255 100644 +--- a/support/include/nfs/export.h ++++ b/support/include/nfs/export.h +@@ -26,6 +26,7 @@ + #define NFSEXP_CROSSMOUNT 0x4000 + #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ + #define NFSEXP_V4ROOT 0x10000 ++#define NFSEXP_PNFS 0x20000 + /* + * All flags supported by the kernel before addition of the + * export_features interface: +diff --git a/support/nfs/exports.c b/support/nfs/exports.c +index 5451ed7..9399a12 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -275,6 +275,7 @@ putexportent(struct exportent *ep) + "no_" : ""); + if (ep->e_flags & NFSEXP_NOREADDIRPLUS) + fprintf(fp, "nordirplus,"); ++ fprintf(fp, "%spnfs,", (ep->e_flags & NFSEXP_PNFS)? "" : "no_"); + if (ep->e_flags & NFSEXP_FSID) { + fprintf(fp, "fsid=%d,", ep->e_fsid); + } +@@ -581,6 +582,10 @@ parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr) + clearflags(NFSEXP_NOACL, active, ep); + else if (strcmp(opt, "no_acl") == 0) + setflags(NFSEXP_NOACL, active, ep); ++ else if (!strcmp(opt, "pnfs")) ++ setflags(NFSEXP_PNFS, active, ep); ++ else if (!strcmp(opt, "no_pnfs")) ++ clearflags(NFSEXP_PNFS, active, ep); + else if (strncmp(opt, "anonuid=", 8) == 0) { + char *oe; + ep->e_anonuid = strtol(opt+8, &oe, 10); +diff --git a/systemd/Makefile.am b/systemd/Makefile.am +new file mode 100644 +index 0000000..fbcabb1 +--- /dev/null ++++ b/systemd/Makefile.am +@@ -0,0 +1,31 @@ ++## Process this file with automake to produce Makefile.in ++ ++MAINTAINERCLEANFILES = Makefile.in ++ ++unit_files = \ ++ 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/README b/systemd/README +index a2a5f06..bbd7790 100644 +--- a/systemd/README ++++ b/systemd/README +@@ -24,7 +24,7 @@ by a suitable 'preset' setting: + is started by /usr/sbin/start-statd which mount.nfs will run + if statd is needed. + +- nfs-blkmap.target ++ nfs-blkmap.service + If enabled, then blkmapd will be run when nfs-client.target is + started. + +diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service +index f470e3d..ddbf4e9 100644 +--- a/systemd/nfs-blkmap.service ++++ b/systemd/nfs-blkmap.service +@@ -5,12 +5,13 @@ Conflicts=umount.target + After=var-lib-nfs-rpc_pipefs.mount + Requires=var-lib-nfs-rpc_pipefs.mount + +-Requisite=nfs-blkmap.target +-After=nfs-blkmap.target +- + PartOf=nfs-utils.service + + [Service] + Type=forking + PIDFile=/var/run/blkmapd.pid ++EnvironmentFile=-/run/sysconfig/nfs-utils + ExecStart=/usr/sbin/blkmapd $BLKMAPDARGS ++ ++[Install] ++WantedBy=nfs-client.target +diff --git a/systemd/nfs-blkmap.target b/systemd/nfs-blkmap.target +deleted file mode 100644 +index fbcc111..0000000 +--- a/systemd/nfs-blkmap.target ++++ /dev/null +@@ -1,8 +0,0 @@ +-[Unit] +-Description= PNFS blkmaping enablement. +-# If this target is enabled, then blkmapd will be started +-# as required. If it is not enabled it won't. +- +-[Install] +-WantedBy=remote-fs.target +-WantedBy=multi-user.target +\ No newline at end of file +diff --git a/systemd/nfs-client.target b/systemd/nfs-client.target +index 9b792a3..8a8300a 100644 +--- a/systemd/nfs-client.target ++++ b/systemd/nfs-client.target +@@ -5,8 +5,7 @@ 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=nfs-blkmap.service rpc-statd-notify.service +-After=nfs-blkmap.service ++Wants=rpc-statd-notify.service + + # GSS services dependencies and ordering + Wants=auth-rpcgss-module.service +diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c +index df4627e..b52afe2 100644 +--- a/utils/blkmapd/device-discovery.c ++++ b/utils/blkmapd/device-discovery.c +@@ -77,16 +77,6 @@ struct bl_disk_path *bl_get_path(const char *filepath, + return tmp; + } + +-/* Check whether valid_path is a substring(partition) of path */ +-int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path) +-{ +- if (!strncmp(valid_path->full_path, path->full_path, +- strlen(valid_path->full_path))) +- return 1; +- +- return 0; +-} +- + /* + * For multipath devices, devices state could be PASSIVE/ACTIVE/PSEUDO, + * where PSEUDO > ACTIVE > PASSIVE. Device with highest state is used to +@@ -95,19 +85,13 @@ int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path) + * If device-mapper multipath support is a must, pseudo devices should + * exist for each multipath device. If not, active device path will be + * chosen for device creation. +- * Treat partition as invalid path. + */ +-int bl_update_path(struct bl_disk_path *path, enum bl_path_state_e state, +- struct bl_disk *disk) ++int bl_update_path(enum bl_path_state_e state, struct bl_disk *disk) + { + struct bl_disk_path *valid_path = disk->valid_path; + +- if (valid_path) { +- if (valid_path->state >= state) { +- if (bl_is_partition(valid_path, path)) +- return 0; +- } +- } ++ if (valid_path && valid_path->state >= state) ++ return 0; + return 1; + } + +@@ -164,15 +148,16 @@ void bl_add_disk(char *filepath) + + dev = sb.st_rdev; + serial = bldev_read_serial(fd, filepath); +- if (dm_is_dm_major(major(dev))) ++ if (!serial) { ++ BL_LOG_ERR("%s: no serial found for %s\n", ++ __func__, filepath); ++ ap_state = BL_PATH_STATE_PASSIVE; ++ } else if (dm_is_dm_major(major(dev))) + ap_state = BL_PATH_STATE_PSEUDO; + else + ap_state = bldev_read_ap_state(fd); + close(fd); + +- if (ap_state != BL_PATH_STATE_ACTIVE) +- return; +- + for (disk = visible_disk_list; disk != NULL; disk = disk->next) { + /* Already scanned or a partition? + * XXX: if released each time, maybe not need to compare +@@ -216,7 +201,7 @@ void bl_add_disk(char *filepath) + path->next = disk->paths; + disk->paths = path; + /* check whether we need to update disk info */ +- if (bl_update_path(path, path->state, disk)) { ++ if (bl_update_path(path->state, disk)) { + disk->dev = dev; + disk->size = size; + disk->valid_path = path; +diff --git a/utils/blkmapd/device-inq.c b/utils/blkmapd/device-inq.c +index eabc70c..c5bf71f 100644 +--- a/utils/blkmapd/device-inq.c ++++ b/utils/blkmapd/device-inq.c +@@ -179,6 +179,7 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + char *buffer; + struct bl_dev_id *dev_root, *dev_id; + unsigned int pos, len, current_id = 0; ++ size_t devid_len = sizeof(struct bl_dev_id) - sizeof(unsigned char); + + status = bldev_inquire_pages(fd, 0x83, &buffer); + if (status) +@@ -189,7 +190,11 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + pos = 0; + current_id = 0; + len = dev_root->len; +- while (pos < (len - sizeof(struct bl_dev_id) + sizeof(unsigned char))) { ++ ++ if (len < devid_len) ++ goto out; ++ ++ while (pos < (len - devid_len)) { + dev_id = (struct bl_dev_id *)&(dev_root->data[pos]); + if ((dev_id->ids & 0xf) < current_id) + continue; +@@ -221,8 +226,7 @@ struct bl_serial *bldev_read_serial(int fd, const char *filename) + } + if (current_id == 3) + break; +- pos += (dev_id->len + sizeof(struct bl_dev_id) - +- sizeof(unsigned char)); ++ pos += (dev_id->len + devid_len); + } + out: + if (!serial_out) +diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c +index 5fe3dff..f53a616 100644 +--- a/utils/blkmapd/device-process.c ++++ b/utils/blkmapd/device-process.c +@@ -181,6 +181,8 @@ static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol) + /* FIXME: should we use better algorithm for disk scan? */ + mapped = verify_sig(disk, sig); + if (mapped) { ++ BL_LOG_INFO("%s: using device %s\n", ++ __func__, disk->valid_path->full_path); + vol->param.bv_dev = disk->dev; + vol->bv_size = disk->size; + break; +diff --git a/utils/blkmapd/dm-device.c b/utils/blkmapd/dm-device.c +index 0f4f148..24ffcbf 100644 +--- a/utils/blkmapd/dm-device.c ++++ b/utils/blkmapd/dm-device.c +@@ -400,6 +400,8 @@ uint64_t dm_device_create(struct bl_volume *vols, int num_vols) + } + dev = node->bv_vols[0]->param.bv_dev; + tmp = table->params; ++ BL_LOG_INFO("%s: major %lu minor %lu", __func__, ++ MAJOR(dev), MINOR(dev)); + if (!dm_format_dev(tmp, DM_PARAMS_LEN, + MAJOR(dev), MINOR(dev))) { + free(table); +@@ -459,6 +461,8 @@ uint64_t dm_device_create(struct bl_volume *vols, int num_vols) + strcpy(table->target_type, "linear"); + tmp = table->params; + dev = node->bv_vols[i]->param.bv_dev; ++ BL_LOG_INFO("%s: major %lu minor %lu", __func__, ++ MAJOR(dev), MINOR(dev)); + if (!dm_format_dev(tmp, DM_PARAMS_LEN, + MAJOR(dev), MINOR(dev))) { + free(table); +diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index 8391615..53e86ec 100644 +--- a/utils/exportfs/exportfs.c ++++ b/utils/exportfs/exportfs.c +@@ -815,6 +815,8 @@ dump(int verbose, int export_format) + c = dumpopt(c, "insecure_locks"); + if (ep->e_flags & NFSEXP_NOACL) + c = dumpopt(c, "no_acl"); ++ if (ep->e_flags & NFSEXP_PNFS) ++ c = dumpopt(c, "pnfs"); + if (ep->e_flags & NFSEXP_FSID) + c = dumpopt(c, "fsid=%d", ep->e_fsid); + if (ep->e_uuid) +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index 3d974d9..59358e6 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -378,6 +378,15 @@ If the client asks for alternative locations for the export point, it + will be given this list of alternatives. (Note that actual replication + of the filesystem must be handled elsewhere.) + ++.TP ++.IR pnfs ++This option allows enables the use of pNFS extension if protocol level ++is NFSv4.1 or higher, and the filesystem supports pNFS exports. With ++pNFS clients can bypass the server and perform I/O directly to storage ++devices. The default can be explicitly requested with the ++.I no_pnfs ++option. ++ + .SS User ID Mapping + .PP + .B nfsd diff --git a/SOURCES/nfs-utils-1.3.0-blkmapd-usage.patch b/SOURCES/nfs-utils-1.3.0-blkmapd-usage.patch new file mode 100644 index 0000000..61fa7d6 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-blkmapd-usage.patch @@ -0,0 +1,60 @@ +diff -up nfs-utils-1.3.0/utils/blkmapd/blkmapd.man.save nfs-utils-1.3.0/utils/blkmapd/blkmapd.man +--- nfs-utils-1.3.0/utils/blkmapd/blkmapd.man.save 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/blkmapd/blkmapd.man 2016-05-17 14:12:08.000000000 -0400 +@@ -9,7 +9,7 @@ + .SH NAME + blkmapd \- pNFS block layout mapping daemon + .SH SYNOPSIS +-.B "blkmapd [-d] [-f]" ++.B "blkmapd [-h] [-d] [-f]" + .SH DESCRIPTION + The + .B blkmapd +@@ -33,6 +33,9 @@ reflect the server topology, and passes + by the pNFS block layout client. + .SH OPTIONS + .TP ++.B -h ++Display usage message. ++.TP + .B -d + Performs device discovery only then exits. + .TP +diff -up nfs-utils-1.3.0/utils/blkmapd/device-discovery.c.save nfs-utils-1.3.0/utils/blkmapd/device-discovery.c +--- nfs-utils-1.3.0/utils/blkmapd/device-discovery.c.save 2016-05-17 14:11:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/blkmapd/device-discovery.c 2016-05-17 14:11:48.000000000 -0400 +@@ -427,7 +427,10 @@ void sig_die(int signal) + BL_LOG_ERR("exit on signal(%d)\n", signal); + exit(1); + } +- ++static void usage(void) ++{ ++ fprintf(stderr, "Usage: blkmapd [-hdf]\n" ); ++} + /* Daemon */ + int main(int argc, char **argv) + { +@@ -435,7 +438,7 @@ int main(int argc, char **argv) + struct stat statbuf; + char pidbuf[64]; + +- while ((opt = getopt(argc, argv, "df")) != -1) { ++ while ((opt = getopt(argc, argv, "hdf")) != -1) { + switch (opt) { + case 'd': + dflag = 1; +@@ -443,6 +446,13 @@ int main(int argc, char **argv) + case 'f': + fg = 1; + break; ++ case 'h': ++ usage(); ++ exit(0); ++ default: ++ usage(); ++ exit(1); ++ + } + } + diff --git a/SOURCES/nfs-utils-1.3.0-daemon_init-warning.patch b/SOURCES/nfs-utils-1.3.0-daemon_init-warning.patch new file mode 100644 index 0000000..ad10dbf --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-daemon_init-warning.patch @@ -0,0 +1,24 @@ +commit 19e6ba690c7e9674dae006cfce89f638c8d8edab +Author: Steve Dickson +Date: Wed Nov 4 16:25:28 2015 -0500 + + mydaemon.c: Removed a warning + + Commit 273b4647 introduced the following warning: + mydaemon.c:125:2: warning: implicit declaration of function 'closelog' + [-Wimplicit-function-declaration] + + Signed-off-by: Steve Dickson + +diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c +index 701cfd9..343e80b 100644 +--- a/support/nfs/mydaemon.c ++++ b/support/nfs/mydaemon.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + #include + + #include "nfslib.h" diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-NULL-pointer-test.patch b/SOURCES/nfs-utils-1.3.0-exportfs-NULL-pointer-test.patch new file mode 100644 index 0000000..f87c7bf --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-NULL-pointer-test.patch @@ -0,0 +1,46 @@ +commit d89e3fc7d3b14dea481bd9af0bca996ced689bf6 +Author: Natanael Copa +Date: Fri Sep 12 13:19:01 2014 -0400 + + exportfs: fix test of NULL pointer in host_pton() + + This fixes the problem reported in: + https://bugzilla.redhat.com/show_bug.cgi?id=1083018 + + Signed-off-by: Natanael Copa + Signed-off-by: Steve Dickson + +diff --git a/support/export/hostname.c b/support/export/hostname.c +index ad595d1..d9153e1 100644 +--- a/support/export/hostname.c ++++ b/support/export/hostname.c +@@ -115,6 +115,11 @@ host_pton(const char *paddr) + * have a real AF_INET presentation address, before invoking + * getaddrinfo(3) to generate the full addrinfo list. + */ ++ if (paddr == NULL) { ++ xlog(D_GENERAL, "%s: passed a NULL presentation address", ++ __func__); ++ return NULL; ++ } + inet4 = 1; + if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) + inet4 = 0; +@@ -123,15 +128,12 @@ host_pton(const char *paddr) + switch (error) { + case 0: + if (!inet4 && ai->ai_addr->sa_family == AF_INET) { ++ xlog(D_GENERAL, "%s: failed to convert %s", ++ __func__, paddr); + freeaddrinfo(ai); + break; + } + return ai; +- case EAI_NONAME: +- if (paddr == NULL) +- xlog(D_GENERAL, "%s: passed a NULL presentation address", +- __func__); +- break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", + __func__, paddr, errno); diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-bufsiz.patch b/SOURCES/nfs-utils-1.3.0-exportfs-bufsiz.patch new file mode 100644 index 0000000..a82e8c8 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-bufsiz.patch @@ -0,0 +1,47 @@ +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2016-05-03 11:06:55.925043000 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2016-05-03 11:11:58.680677000 -0400 +@@ -508,9 +508,10 @@ unexportfs(char *arg, int verbose) + + static int can_test(void) + { +- char buf[1024]; ++ char buf[1024] = { 0 }; + int fd; + int n; ++ size_t bufsiz = sizeof(buf); + + fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); + if (fd < 0) +@@ -523,9 +524,9 @@ static int can_test(void) + * commit 2f74f972 (sunrpc: prepare NFS for 2038). + */ + if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS) +- sprintf(buf, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); ++ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); + else +- sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); ++ snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); + + n = write(fd, buf, strlen(buf)); + close(fd); +@@ -541,7 +542,8 @@ static int can_test(void) + + static int test_export(char *path, int with_fsid) + { +- char buf[1024]; ++ /* beside max path, buf size should take protocol str into account */ ++ char buf[NFS_MAXPATHLEN+1+64] = { 0 }; + char *bp = buf; + int len = sizeof(buf); + int fd, n; +@@ -766,7 +768,8 @@ dumpopt(char c, char *fmt, ...) + static void + dump(int verbose, int export_format) + { +- char buf[1024]; ++ /* buf[] size should >= sizeof(struct exportent->e_path) */ ++ char buf[NFS_MAXPATHLEN+1] = { 0 }; + char *bp; + int len; + nfs_export *exp; diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-empty-exports.patch b/SOURCES/nfs-utils-1.3.0-exportfs-empty-exports.patch new file mode 100644 index 0000000..9d422a4 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-empty-exports.patch @@ -0,0 +1,119 @@ +diff --git a/support/export/export.c b/support/export/export.c +index ce714d4..e1bebce 100644 +--- a/support/export/export.c ++++ b/support/export/export.c +@@ -69,8 +69,9 @@ 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; +@@ -82,16 +83,16 @@ export_read(char *fname) + while ((eep = getexportent(0,1)) != NULL) { + exp = export_lookup(eep->e_hostname, eep->e_path, 0); + if (!exp) { +- exp = export_create(eep, 0); +- if (exp) ++ if (export_create(eep, 0)) ++ /* possible complaints already logged */ + volumes++; + } + else + warn_duplicated_exports(exp, eep); + } + endexportent(); +- if (volumes == 0) +- xlog(L_ERROR, "No file systems exported!"); ++ ++ return volumes; + } + + /** +diff --git a/support/include/exportfs.h b/support/include/exportfs.h +index 97b2327..faa9f0b 100644 +--- a/support/include/exportfs.h ++++ b/support/include/exportfs.h +@@ -133,7 +133,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/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index c06f2aa..b7d8578 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); + +@@ -185,8 +185,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) +@@ -699,21 +702,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]; +@@ -743,14 +747,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/SOURCES/nfs-utils-1.3.0-exportfs-hostnames.patch b/SOURCES/nfs-utils-1.3.0-exportfs-hostnames.patch new file mode 100644 index 0000000..9dce081 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-hostnames.patch @@ -0,0 +1,55 @@ +diff --git a/support/export/hostname.c b/support/export/hostname.c +index cdf9e76..816b098 100644 +--- a/support/export/hostname.c ++++ b/support/export/hostname.c +@@ -230,7 +230,7 @@ host_canonname(const struct sockaddr *sap) + default: + (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NUMERICHOST); +- xlog(D_GENERAL, "%s: failed to resolve %s: %s", ++ xlog(D_PARSE, "%s: failed to resolve %s: %s", + __func__, buf, gai_strerror(error)); + return NULL; + } +diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index 614c3dc..bc3f00f 100644 +--- a/utils/exportfs/exportfs.c ++++ b/utils/exportfs/exportfs.c +@@ -108,11 +108,14 @@ main(int argc, char **argv) + xlog_stderr(1); + xlog_syslog(0); + +- while ((c = getopt(argc, argv, "afhio:ruvs")) != EOF) { ++ while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) { + switch(c) { + case 'a': + f_all = 1; + break; ++ case 'd': ++ xlog_sconfig(optarg, 1); ++ break; + case 'f': + force_flush = 1; + break; +@@ -869,6 +872,6 @@ error(nfs_export *exp, int err) + static void + usage(const char *progname, int n) + { +- fprintf(stderr, "usage: %s [-afhioruvs] [host:/path]\n", progname); ++ fprintf(stderr, "usage: %s [-adfhioruvs] [host:/path]\n", progname); + exit(n); + } +diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man +index 75d952a..fdf9260 100644 +--- a/utils/exportfs/exportfs.man ++++ b/utils/exportfs/exportfs.man +@@ -88,6 +88,9 @@ appropriate export entry for the host given in + to be added to the kernel's export table. + .SH OPTIONS + .TP ++.B \-d kind " or " \-\-debug kind ++Turn on debugging. Valid kinds are: all, auth, call, general and parse. ++.TP + .B -a + Export or unexport all directories. + .TP diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-ipv6-arg.patch b/SOURCES/nfs-utils-1.3.0-exportfs-ipv6-arg.patch new file mode 100644 index 0000000..e6390a9 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-ipv6-arg.patch @@ -0,0 +1,87 @@ +commit 7f5f7fe118b87fbc6a2c6cc52aff808564d907a4 +Author: Todd Vierling +Date: Fri Sep 19 10:32:55 2014 -0400 + + exportfs: Properly parse IPv6 literal strings with null termination + + The original implementation was using strncpy() with a truncation + length to an uninitialized stack buffer, leaving a string that + was only null terminated by luck. + + While here, change to use no-copy semantics (no extra buffer) to + avoid buffer overflows altogether. exportfs already modifies argv + contents elsewhere, so this doesn't break anything anew. + + Fixes: 4663c648 (exportfs: Support raw IPv6 addresses with + "client:/path") + + Signed-off-by: Todd Vierling + Reviewed-by: Chuck Lever + Signed-off-by: Steve Dickson + +diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index e7d1ac8..bdea12b 100644 +--- a/utils/exportfs/exportfs.c ++++ b/utils/exportfs/exportfs.c +@@ -351,16 +351,15 @@ static int exportfs_generic(char *arg, char *options, int verbose) + + static int exportfs_ipv6(char *arg, char *options, int verbose) + { +- char *path, *c, hname[NI_MAXHOST + strlen("/128")]; ++ char *path, *c; + + arg++; + c = strchr(arg, ']'); + if (c == NULL) + return 1; +- strncpy(hname, arg, c - arg); + + /* no colon means this is a wildcarded DNS hostname */ +- if (strchr(hname, ':') == NULL) ++ if (memchr(arg, ':', c - arg) == NULL) + return exportfs_generic(--arg, options, verbose); + + path = strstr(c, ":/"); +@@ -370,9 +369,9 @@ static int exportfs_ipv6(char *arg, char *options, int verbose) + + /* if there's anything between the closing brace and the + * path separator, it's probably a prefix length */ +- strcat(hname, ++c); ++ memmove(c, c + 1, path - c); + +- exportfs_parsed(hname, path, options, verbose); ++ exportfs_parsed(arg, path, options, verbose); + return 0; + } + +@@ -458,16 +457,15 @@ static int unexportfs_generic(char *arg, int verbose) + + static int unexportfs_ipv6(char *arg, int verbose) + { +- char *path, *c, hname[NI_MAXHOST + strlen("/128")]; ++ char *path, *c; + + arg++; + c = strchr(arg, ']'); + if (c == NULL) + return 1; +- strncpy(hname, arg, c - arg); + + /* no colon means this is a wildcarded DNS hostname */ +- if (strchr(hname, ':') == NULL) ++ if (memchr(arg, ':', c - arg) == NULL) + return unexportfs_generic(--arg, verbose); + + path = strstr(c, ":/"); +@@ -477,9 +475,9 @@ static int unexportfs_ipv6(char *arg, int verbose) + + /* if there's anything between the closing brace and the + * path separator, it's probably a prefix length */ +- strcat(hname, ++c); ++ memmove(c, c + 1, path - c); + +- unexportfs_parsed(hname, path, verbose); ++ unexportfs_parsed(arg, path, verbose); + return 0; + } + diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-noreaddirplus.patch b/SOURCES/nfs-utils-1.3.0-exportfs-noreaddirplus.patch new file mode 100644 index 0000000..bca0510 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-noreaddirplus.patch @@ -0,0 +1,83 @@ +commit 4017afe28d640c535109576bd149bc7e0345f075 +Author: Rajesh Ghanekar +Date: Wed Aug 20 14:00:59 2014 -0400 + + nfs-utils: Allow turning off nfsv3 readdir_plus + + One of our customer's application only needs file names, not file + attributes. With directories having 10K+ inodes (assuming buffer cache + has directory blocks cached having file names, but inode cache is + limited and hence need eviction of older cached inodes), older inodes + are evicted periodically. So if they keep on doing readdir(2) from NSF + client on multiple directories, some directory's files are periodically + removed from inode cache and hence new readdir(2) on same directory + requires disk access to bring back inodes again to inode cache. + + As READDIRPLUS request fetches attributes also, doing getattr on each + file on server, it causes unnecessary disk accesses. If READDIRPLUS on + NFS client is returned with -ENOTSUPP, NFS client uses READDIR request + which just gets the names of the files in a directory, not attributes, + hence avoiding disk accesses on server. + + There's already a corresponding client-side mount option, but an export + option reduces the need for configuration across multiple clients. + + This flag affects NFSv3 only. If it turns out it's needed for NFSv4 as + well then we may have to figure out how to extend the behavior to NFSv4, + but it's not currently obvious how to do that. + + Signed-off-by: Rajesh Ghanekar + Signed-off-by: Steve Dickson + +diff --git a/support/include/nfs/export.h b/support/include/nfs/export.h +index 1547a87..2f59e6a 100644 +--- a/support/include/nfs/export.h ++++ b/support/include/nfs/export.h +@@ -17,7 +17,8 @@ + #define NFSEXP_ALLSQUASH 0x0008 + #define NFSEXP_ASYNC 0x0010 + #define NFSEXP_GATHERED_WRITES 0x0020 +-/* 40, 80, 100 unused */ ++#define NFSEXP_NOREADDIRPLUS 0x0040 ++/* 80, 100 unused */ + #define NFSEXP_NOHIDE 0x0200 + #define NFSEXP_NOSUBTREECHECK 0x0400 + #define NFSEXP_NOAUTHNLM 0x0800 +diff --git a/support/nfs/exports.c b/support/nfs/exports.c +index 819d6c4..eb782b9 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -273,6 +273,8 @@ putexportent(struct exportent *ep) + "in" : ""); + fprintf(fp, "%sacl,", (ep->e_flags & NFSEXP_NOACL)? + "no_" : ""); ++ if (ep->e_flags & NFSEXP_NOREADDIRPLUS) ++ fprintf(fp, "nordirplus,"); + if (ep->e_flags & NFSEXP_FSID) { + fprintf(fp, "fsid=%d,", ep->e_fsid); + } +@@ -539,6 +541,8 @@ parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr) + clearflags(NFSEXP_ASYNC, active, ep); + else if (!strcmp(opt, "async")) + setflags(NFSEXP_ASYNC, active, ep); ++ else if (!strcmp(opt, "nordirplus")) ++ setflags(NFSEXP_NOREADDIRPLUS, active, ep); + else if (!strcmp(opt, "nohide")) + setflags(NFSEXP_NOHIDE, active, ep); + else if (!strcmp(opt, "hide")) +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index e8b29df..3d974d9 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -360,6 +360,11 @@ supported so the same configuration can be made to work on old and new + kernels alike. + + .TP ++.IR nordirplus ++This option will disable READDIRPLUS request handling. When set, ++READDIRPLUS requests from NFS clients return NFS3ERR_NOTSUPP, and ++clients fall back on READDIR. This option affects only NFSv3 clients. ++.TP + .IR refer= path@host[+host][:path@host[+host]] + A client referencing the export point will be directed to choose from + the given list an alternative location for the filesystem. diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-path-comp.patch b/SOURCES/nfs-utils-1.3.0-exportfs-path-comp.patch new file mode 100644 index 0000000..9216eb4 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-path-comp.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2017-06-15 11:28:59.541764508 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2017-06-15 11:30:04.699701243 -0400 +@@ -421,6 +421,8 @@ unexportfs_parsed(char *hname, char *pat + nlen--; + + for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { ++ if (strlen(exp->m_export.e_path) != nlen) ++ continue; + if (path && strncmp(path, exp->m_export.e_path, nlen)) + continue; + if (htype != exp->m_client->m_type) diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-redundant.patch b/SOURCES/nfs-utils-1.3.0-exportfs-redundant.patch new file mode 100644 index 0000000..78ef5c3 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-redundant.patch @@ -0,0 +1,41 @@ +diff -up nfs-utils-1.3.0/support/nfs/exports.c.orig nfs-utils-1.3.0/support/nfs/exports.c +--- nfs-utils-1.3.0/support/nfs/exports.c.orig 2017-02-27 18:24:26.485237519 -0500 ++++ nfs-utils-1.3.0/support/nfs/exports.c 2017-02-27 18:25:49.296652027 -0500 +@@ -197,7 +197,6 @@ static const struct secinfo_flag_display + 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" }, +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2017-02-27 18:24:26.429237915 -0500 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2017-02-27 18:25:49.297652020 -0500 +@@ -814,20 +814,18 @@ dump(int verbose, int export_format) + c = dumpopt(c, "rw"); + if (ep->e_flags & NFSEXP_ASYNC) + c = dumpopt(c, "async"); ++ else ++ c = dumpopt(c, "sync"); + if (ep->e_flags & NFSEXP_GATHERED_WRITES) + c = dumpopt(c, "wdelay"); ++ else ++ c = dumpopt(c, "no_wdelay"); + if (ep->e_flags & NFSEXP_NOHIDE) + c = dumpopt(c, "nohide"); ++ else ++ c = dumpopt(c, "hide"); + if (ep->e_flags & NFSEXP_CROSSMOUNT) + c = dumpopt(c, "crossmnt"); +- if (ep->e_flags & NFSEXP_INSECURE_PORT) +- c = dumpopt(c, "insecure"); +- if (ep->e_flags & NFSEXP_ROOTSQUASH) +- c = dumpopt(c, "root_squash"); +- else +- c = dumpopt(c, "no_root_squash"); +- if (ep->e_flags & NFSEXP_ALLSQUASH) +- c = dumpopt(c, "all_squash"); + if (ep->e_flags & NFSEXP_NOSUBTREECHECK) + c = dumpopt(c, "no_subtree_check"); + if (ep->e_flags & NFSEXP_NOAUTHNLM) diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-securitylabel.patch b/SOURCES/nfs-utils-1.3.0-exportfs-securitylabel.patch new file mode 100644 index 0000000..33a5ef7 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-securitylabel.patch @@ -0,0 +1,64 @@ +diff -up nfs-utils-1.3.0/support/include/nfs/export.h.orig nfs-utils-1.3.0/support/include/nfs/export.h +--- nfs-utils-1.3.0/support/include/nfs/export.h.orig 2017-03-27 10:07:41.440397336 -0400 ++++ nfs-utils-1.3.0/support/include/nfs/export.h 2017-03-27 10:08:57.195772235 -0400 +@@ -18,7 +18,8 @@ + #define NFSEXP_ASYNC 0x0010 + #define NFSEXP_GATHERED_WRITES 0x0020 + #define NFSEXP_NOREADDIRPLUS 0x0040 +-/* 80, 100 unused */ ++#define NFSEXP_SECURITY_LABEL 0x0080 ++/* 0x100 unused */ + #define NFSEXP_NOHIDE 0x0200 + #define NFSEXP_NOSUBTREECHECK 0x0400 + #define NFSEXP_NOAUTHNLM 0x0800 +diff -up nfs-utils-1.3.0/support/nfs/exports.c.orig nfs-utils-1.3.0/support/nfs/exports.c +--- nfs-utils-1.3.0/support/nfs/exports.c.orig 2017-03-27 10:07:41.549399315 -0400 ++++ nfs-utils-1.3.0/support/nfs/exports.c 2017-03-27 10:08:58.441794848 -0400 +@@ -274,6 +274,8 @@ putexportent(struct exportent *ep) + "no_" : ""); + if (ep->e_flags & NFSEXP_NOREADDIRPLUS) + fprintf(fp, "nordirplus,"); ++ if (ep->e_flags & NFSEXP_SECURITY_LABEL) ++ fprintf(fp, "security_label,"); + fprintf(fp, "%spnfs,", (ep->e_flags & NFSEXP_PNFS)? "" : "no_"); + if (ep->e_flags & NFSEXP_FSID) { + fprintf(fp, "fsid=%d,", ep->e_fsid); +@@ -543,6 +545,8 @@ parseopts(char *cp, struct exportent *ep + setflags(NFSEXP_ASYNC, active, ep); + else if (!strcmp(opt, "nordirplus")) + setflags(NFSEXP_NOREADDIRPLUS, active, ep); ++ else if (!strcmp(opt, "security_label")) ++ setflags(NFSEXP_SECURITY_LABEL, active, ep); + else if (!strcmp(opt, "nohide")) + setflags(NFSEXP_NOHIDE, active, ep); + else if (!strcmp(opt, "hide")) +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2017-03-27 10:08:58.441794848 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2017-03-27 10:11:00.939046616 -0400 +@@ -835,6 +835,8 @@ dump(int verbose, int export_format) + c = dumpopt(c, "no_subtree_check"); + if (ep->e_flags & NFSEXP_NOAUTHNLM) + c = dumpopt(c, "insecure_locks"); ++ if (ep->e_flags & NFSEXP_SECURITY_LABEL) ++ c = dumpopt(c, "security_label"); + if (ep->e_flags & NFSEXP_NOACL) + c = dumpopt(c, "no_acl"); + if (ep->e_flags & NFSEXP_PNFS) +diff -up nfs-utils-1.3.0/utils/exportfs/exports.man.orig nfs-utils-1.3.0/utils/exportfs/exports.man +--- nfs-utils-1.3.0/utils/exportfs/exports.man.orig 2017-03-27 10:07:41.515398698 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exports.man 2017-03-27 10:08:58.441794848 -0400 +@@ -417,6 +417,14 @@ devices. The default can be explicitly r + .I no_pnfs + option. + ++.TP ++.IR security_label ++With this option set, clients using NFSv4.2 or higher will be able to ++set and retrieve security labels (such as those used by SELinux). This ++will only work if all clients use a consistent security policy. Note ++that early kernels did not support this export option, and instead ++enabled security labels by default. ++ + .SS User ID Mapping + .PP + .B nfsd diff --git a/SOURCES/nfs-utils-1.3.0-exportfs-slashes.patch b/SOURCES/nfs-utils-1.3.0-exportfs-slashes.patch new file mode 100644 index 0000000..0c6c6f0 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-exportfs-slashes.patch @@ -0,0 +1,22 @@ +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2016-05-03 10:50:17.226864000 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2016-05-03 10:51:49.848199000 -0400 +@@ -402,8 +402,17 @@ unexportfs_parsed(char *hname, char *pat + hname = ai->ai_canonname; + } + ++ /* ++ * It's possible the specified path ends with a '/'. But ++ * the entry from exportlist won't has the trailing '/', ++ * so need to deal with it. ++ */ ++ size_t nlen = strlen(path); ++ while (path[nlen - 1] == '/') ++ nlen--; ++ + for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { +- if (path && strcmp(path, exp->m_export.e_path)) ++ if (path && strncmp(path, exp->m_export.e_path, nlen)) + continue; + if (htype != exp->m_client->m_type) + continue; diff --git a/SOURCES/nfs-utils-1.3.0-gssd-default-tcp.patch b/SOURCES/nfs-utils-1.3.0-gssd-default-tcp.patch new file mode 100644 index 0000000..cdea6ec --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssd-default-tcp.patch @@ -0,0 +1,35 @@ +commit 1ee2184248251ff44ae1ba557f12151cb8cf93ff +Author: Chuck Lever +Date: Mon Nov 2 08:47:41 2015 -0500 + + gssd: Make TCP the default protocol for GSSD connections. + + No failure case if gssd doesn't recognize the kernel's requested + protocol. Caught with "protocol=rdma" upcall. + + Signed-off-by: Chuck Lever + Signed-off-by: Steve Dickson + +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index 11168b2..cee8991 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -348,16 +348,9 @@ create_auth_rpc_client(struct clnt_info *clp, + printerr(2, "creating %s client for server %s\n", clp->protocol, + clp->servername); + +- if ((strcmp(clp->protocol, "tcp")) == 0) { +- protocol = IPPROTO_TCP; +- } else if ((strcmp(clp->protocol, "udp")) == 0) { ++ protocol = IPPROTO_TCP; ++ if ((strcmp(clp->protocol, "udp")) == 0) + protocol = IPPROTO_UDP; +- } else { +- printerr(0, "WARNING: unrecognized protocol, '%s', requested " +- "for connection to server %s for user with uid %d\n", +- clp->protocol, clp->servername, uid); +- goto out_fail; +- } + + switch (addr->sa_family) { + case AF_INET: diff --git a/SOURCES/nfs-utils-1.3.0-gssd-noclear-retval.patch b/SOURCES/nfs-utils-1.3.0-gssd-noclear-retval.patch new file mode 100644 index 0000000..c19d730 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssd-noclear-retval.patch @@ -0,0 +1,27 @@ +commit a705076172b274463563416adffe55f129740267 +Author: Steve Dickson +Date: Thu Jul 30 17:06:39 2015 -0400 + + rpc.gssd: Only clear the retval if it has not been set + + In gssd_search_krb5_keytab() an error code can be + cleared by blindly setting retval to zero. + + Reported-by: Jianhong Yin + Signed-off-by: Steve Dickson + +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index f1ebc0d..ecf17a2 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -772,7 +772,9 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, + "keytab '%s'\n", k5err, kt_name); + } + +- retval = 0; ++ /* Only clear the retval if has not been set */ ++ if (retval < 0) ++ retval = 0; + out: + free(k5err); + return retval; diff --git a/SOURCES/nfs-utils-1.3.0-gssd-rdma-to-tcp.patch b/SOURCES/nfs-utils-1.3.0-gssd-rdma-to-tcp.patch new file mode 100644 index 0000000..24a6986 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssd-rdma-to-tcp.patch @@ -0,0 +1,26 @@ +diff -up nfs-utils-1.3.0/utils/gssd/gssd.c.orig nfs-utils-1.3.0/utils/gssd/gssd.c +--- nfs-utils-1.3.0/utils/gssd/gssd.c.orig 2017-02-28 14:24:20.296676493 -0500 ++++ nfs-utils-1.3.0/utils/gssd/gssd.c 2017-02-28 14:45:36.140482510 -0500 +@@ -305,6 +305,22 @@ gssd_read_service_info(int dirfd, struct + goto fail; + } + ++ /* ++ * The user space RPC library has no support for ++ * RPC-over-RDMA at this time, so change 'rdma' ++ * to 'tcp', and '20049' to '2049'. ++ */ ++ if (strcmp(protoname, "rdma") == 0) { ++ free(protoname); ++ protoname = strdup("tcp"); ++ if (!protoname) ++ goto fail; ++ free(port); ++ port = strdup("2049"); ++ if (!port) ++ goto fail; ++ } ++ + if (!gssd_addrstr_to_sockaddr((struct sockaddr *)&clp->addr, + address, port ? port : "")) + goto fail; diff --git a/SOURCES/nfs-utils-1.3.0-gssd-tgt-flood.patch b/SOURCES/nfs-utils-1.3.0-gssd-tgt-flood.patch new file mode 100644 index 0000000..5dfef5c --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssd-tgt-flood.patch @@ -0,0 +1,287 @@ +diff -up nfs-utils-1.3.0/utils/gssd/gssd_proc.c.old nfs-utils-1.3.0/utils/gssd/gssd_proc.c +--- nfs-utils-1.3.0/utils/gssd/gssd_proc.c.old 2015-09-24 09:48:40.833593000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd_proc.c 2015-09-24 09:50:58.747069000 -0400 +@@ -1023,6 +1023,113 @@ change_identity(uid_t uid) + return 0; + } + ++AUTH * ++krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, ++ int *downcall_err, int *chg_err, CLIENT **rpc_clnt) ++{ ++ AUTH *auth = NULL; ++ gss_cred_id_t gss_cred; ++ char **dname; ++ int err, resp = -1; ++ ++ printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", ++ uid, tgtname); ++ ++ *chg_err = change_identity(uid); ++ if (*chg_err) { ++ printerr(0, "WARNING: failed to change identity: %s", ++ strerror(*chg_err)); ++ goto out; ++ } ++ ++ /** Tell krb5 gss which credentials cache to use. ++ * Try first to acquire credentials directly via GSSAPI ++ */ ++ err = gssd_acquire_user_cred(&gss_cred); ++ if (err == 0) ++ 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 ++ */ ++ for (dname = ccachesearch; resp != 0 && *dname != NULL; dname++) { ++ err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, ++ *dname); ++ if (err == -EKEYEXPIRED) ++ *downcall_err = -EKEYEXPIRED; ++ else if (err == 0) ++ resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, ++ &auth, uid,AUTHTYPE_KRB5, ++ GSS_C_NO_CREDENTIAL); ++ } ++ ++out: ++ return auth; ++} ++ ++AUTH * ++krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, ++ char *service, CLIENT **rpc_clnt) ++{ ++ AUTH *auth = NULL; ++ char **credlist = NULL; ++ char **ccname; ++ int nocache = 0; ++ int success = 0; ++ ++ printerr(1, "krb5_use_machine_creds: uid %d tgtname %s\n", ++ uid, tgtname); ++ ++ do { ++ gssd_refresh_krb5_machine_credential(clp->servername, NULL, ++ service); ++ /* ++ * Get a list of credential cache names and try each ++ * of them until one works or we've tried them all ++ */ ++ if (gssd_get_krb5_machine_cred_list(&credlist)) { ++ printerr(0, "ERROR: No credentials found " ++ "for connection to server %s\n", ++ clp->servername); ++ goto out; ++ } ++ for (ccname = credlist; ccname && *ccname; ccname++) { ++ gssd_setup_krb5_machine_gss_ccache(*ccname); ++ if ((create_auth_rpc_client(clp, tgtname, rpc_clnt, ++ &auth, uid, ++ AUTHTYPE_KRB5, ++ GSS_C_NO_CREDENTIAL)) == 0) { ++ /* Success! */ ++ success++; ++ break; ++ } ++ printerr(2, "WARNING: Failed to create machine krb5" ++ "context with cred cache %s for server %s\n", ++ *ccname, clp->servername); ++ } ++ gssd_free_krb5_machine_cred_list(credlist); ++ if (!success) { ++ if(nocache == 0) { ++ nocache++; ++ printerr(2, "WARNING: Machine cache prematurely" "expired or corrupted trying to" ++ "recreate cache for server %s\n", ++ clp->servername); ++ } else { ++ printerr(1, "WARNING: Failed to create machine" ++ "krb5 context with any credentials" ++ "cache for server %s\n", ++ clp->servername); ++ goto out; ++ } ++ } ++ } while(!success); ++ ++out: ++ return auth; ++} ++ + /* + * this code uses the userland rpcsec gss library to create a krb5 + * context on behalf of the kernel +@@ -1035,40 +1142,13 @@ process_krb5_upcall(struct clnt_info *cl + AUTH *auth = NULL; + struct authgss_private_data pd; + gss_buffer_desc token; +- char **credlist = NULL; +- char **ccname; +- char **dirname; +- int create_resp = -1; + int err, downcall_err = -EACCES; +- gss_cred_id_t gss_cred; + OM_uint32 maj_stat, min_stat, lifetime_rec; +- pid_t pid; ++ pid_t pid, childpid = -1; + gss_name_t gacceptor = GSS_C_NO_NAME; + gss_OID mech; + gss_buffer_desc acceptor = {0}; + +- pid = fork(); +- switch(pid) { +- case 0: +- /* Child: fall through to rest of function */ +- break; +- case -1: +- /* fork() failed! */ +- printerr(0, "WARNING: unable to fork() to handle upcall: %s\n", +- strerror(errno)); +- return; +- default: +- /* Parent: just wait on child to exit and return */ +- do { +- pid = wait(&err); +- } while(pid == -1 && errno != -ECHILD); +- +- if (WIFSIGNALED(err)) +- printerr(0, "WARNING: forked child was killed with signal %d\n", +- WTERMSIG(err)); +- return; +- } +- + printerr(1, "handling krb5 upcall (%s)\n", clp->dirname); + + token.length = 0; +@@ -1101,76 +1181,48 @@ process_krb5_upcall(struct clnt_info *cl + if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && + service == NULL)) { + +- err = change_identity(uid); +- if (err) { +- printerr(0, "WARNING: failed to change identity: %s", +- strerror(err)); +- goto out_return_error; +- } ++ /* already running as uid 0 */ ++ if (uid == 0) ++ goto no_fork; ++ ++ pid = fork(); ++ switch(pid) { ++ case 0: ++ /* Child: fall through to rest of function */ ++ childpid = getpid(); ++ unsetenv("KRB5CCNAME"); ++ printerr(1, "CHILD forked pid %d \n", childpid); ++ break; ++ case -1: ++ /* fork() failed! */ ++ printerr(0, "WARNING: unable to fork() to handle" ++ "upcall: %s\n", strerror(errno)); ++ return; ++ default: ++ /* Parent: just wait on child to exit and return */ ++ do { ++ pid = wait(&err); ++ } while(pid == -1 && errno != -ECHILD); + +- /* Tell krb5 gss which credentials cache to use */ +- /* Try first to acquire credentials directly via GSSAPI */ +- err = gssd_acquire_user_cred(&gss_cred); +- if (!err) +- 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 */ +- for (dirname = ccachesearch; create_resp != 0 && *dirname != NULL; dirname++) { +- err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname); +- if (err == -EKEYEXPIRED) +- downcall_err = -EKEYEXPIRED; +- else if (!err) +- create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, +- AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL); ++ if (WIFSIGNALED(err)) ++ printerr(0, "WARNING: forked child was killed" ++ "with signal %d\n", WTERMSIG(err)); ++ return; + } ++no_fork: ++ ++ auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err, ++ &err, &rpc_clnt); ++ if (err) ++ goto out_return_error; + } +- if (create_resp != 0) { ++ if (auth == NULL) { + if (uid == 0 && (root_uses_machine_creds == 1 || + service != NULL)) { +- int nocache = 0; +- int success = 0; +- do { +- gssd_refresh_krb5_machine_credential(clp->servername, +- NULL, service); +- /* +- * Get a list of credential cache names and try each +- * of them until one works or we've tried them all +- */ +- if (gssd_get_krb5_machine_cred_list(&credlist)) { +- printerr(0, "ERROR: No credentials found " +- "for connection to server %s\n", +- clp->servername); +- goto out_return_error; +- } +- for (ccname = credlist; ccname && *ccname; ccname++) { +- gssd_setup_krb5_machine_gss_ccache(*ccname); +- if ((create_auth_rpc_client(clp, tgtname, &rpc_clnt, +- &auth, uid, +- AUTHTYPE_KRB5, +- GSS_C_NO_CREDENTIAL)) == 0) { +- /* Success! */ +- success++; +- break; +- } +- printerr(2, "WARNING: Failed to create machine krb5 context " +- "with credentials cache %s for server %s\n", +- *ccname, clp->servername); +- } +- gssd_free_krb5_machine_cred_list(credlist); +- if (!success) { +- if(nocache == 0) { +- nocache++; +- printerr(2, "WARNING: Machine cache is prematurely expired or corrupted " +- "trying to recreate cache for server %s\n", clp->servername); +- } else { +- printerr(1, "WARNING: Failed to create machine krb5 context " +- "with any credentials cache for server %s\n", +- clp->servername); +- goto out_return_error; +- } +- } +- } while(!success); ++ auth = krb5_use_machine_creds(clp, uid, tgtname, ++ service, &rpc_clnt); ++ if (auth == NULL) ++ goto out_return_error; + } else { + printerr(1, "WARNING: Failed to create krb5 context " + "for user with uid %d for server %s\n", +@@ -1225,7 +1277,12 @@ out: + AUTH_DESTROY(auth); + if (rpc_clnt) + clnt_destroy(rpc_clnt); +- exit(0); ++ ++ pid = getpid(); ++ if (pid == childpid) ++ exit(0); ++ else ++ return; + + out_return_error: + do_error_downcall(fd, uid, downcall_err); diff --git a/SOURCES/nfs-utils-1.3.0-gssd-thread-safe.patch b/SOURCES/nfs-utils-1.3.0-gssd-thread-safe.patch new file mode 100644 index 0000000..6f5fd86 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssd-thread-safe.patch @@ -0,0 +1,69 @@ +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index 646d7e3..14cf7b8 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -728,10 +728,18 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + char *target = NULL; + char *service = NULL; + char *enctypes = NULL; ++ char *upcall_str; ++ char *pbuf = info->lbuf; + + printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); + +- for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) { ++ upcall_str = strdup(info->lbuf); ++ if (upcall_str == NULL) { ++ printerr(0, "ERROR: malloc failure\n"); ++ goto out_nomem; ++ } ++ ++ while ((p = strsep(&pbuf, " "))) { + if (!strncmp(p, "mech=", strlen("mech="))) + mech = p + strlen("mech="); + else if (!strncmp(p, "uid=", strlen("uid="))) +@@ -747,7 +755,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + if (!mech || strlen(mech) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find gss mechanism name " +- "in upcall string '%s'\n", info->lbuf); ++ "in upcall string '%s'\n", upcall_str); + goto out; + } + +@@ -760,7 +768,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + if (!uidstr) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find uid " +- "in upcall string '%s'\n", info->lbuf); ++ "in upcall string '%s'\n", upcall_str); + goto out; + } + +@@ -773,7 +781,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + if (target && strlen(target) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse target name " +- "in upcall string '%s'\n", info->lbuf); ++ "in upcall string '%s'\n", upcall_str); + goto out; + } + +@@ -788,7 +796,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + if (service && strlen(service) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse service type " +- "in upcall string '%s'\n", info->lbuf); ++ "in upcall string '%s'\n", upcall_str); + goto out; + } + +@@ -801,6 +809,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + do_error_downcall(clp->gssd_fd, uid, -EACCES); + } + out: ++ free(upcall_str); ++out_nomem: + free(info); + return; + } diff --git a/SOURCES/nfs-utils-1.3.0-gssproxy.patch b/SOURCES/nfs-utils-1.3.0-gssproxy.patch new file mode 100644 index 0000000..585cf10 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssproxy.patch @@ -0,0 +1,60 @@ +diff -up nfs-utils-1.3.0/systemd/auth-rpcgss-module.service.orig nfs-utils-1.3.0/systemd/auth-rpcgss-module.service +--- nfs-utils-1.3.0/systemd/auth-rpcgss-module.service.orig 2014-09-30 14:51:14.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/auth-rpcgss-module.service 2014-09-30 14:51:14.000000000 -0400 +@@ -0,0 +1,15 @@ ++# We want to start gss-proxy on kernels that support it and rpc.svcgssd ++# on those that don't. Those services check for support by checking ++# for existence of the path /proc/net/rpc/use-gss-proxy. Before they ++# can perform that check, they need this module loaded. (Unless ++# rpcsec_gss support is built directly into the kernel, in which case this ++# unit will fail. But that's OK.) ++[Unit] ++Description=Kernel Module supporting RPCSEC_GSS ++Before=gssproxy.service rpc-svcgssd.service rpc-gssd.service ++Wants=gssproxy.service rpc-svcgssd.service rpc-gssd.service ++ConditionPathExists=/etc/krb5.keytab ++ ++[Service] ++Type=oneshot ++ExecStart=/sbin/modprobe -q auth_rpcgss +diff -up nfs-utils-1.3.0/systemd/nfs-client.target.orig nfs-utils-1.3.0/systemd/nfs-client.target +--- nfs-utils-1.3.0/systemd/nfs-client.target.orig 2014-09-30 14:51:14.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-client.target 2014-09-30 14:51:55.000000000 -0400 +@@ -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 + Wants=nfs-blkmap.service rpc-statd-notify.service +-After=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 -up nfs-utils-1.3.0/systemd/nfs-server.service.orig nfs-utils-1.3.0/systemd/nfs-server.service +--- nfs-utils-1.3.0/systemd/nfs-server.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-server.service 2014-09-30 14:51:14.000000000 -0400 +@@ -2,14 +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 rpc-gssd.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 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/SOURCES/nfs-utils-1.3.0-hostpton-eainoname.patch b/SOURCES/nfs-utils-1.3.0-hostpton-eainoname.patch new file mode 100644 index 0000000..3484c1f --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-hostpton-eainoname.patch @@ -0,0 +1,26 @@ +commit 23d26f9c9fd94406d0c1f4365e6180d59b744861 +Author: Scott Mayhew +Date: Mon Nov 2 08:45:09 2015 -0500 + + exportfs: Restore the EAI_NONAME check in host_pton() + + Commit d89e3fc7 removed the EAI_NONAME check altogether instead of just + moving the NULL check. This causes exportfs -u to incorrectly exit + with 1 whenever there's more than one MCL_FQDN export in the exportlist. + + Signed-off-by: Scott Mayhew + Signed-off-by: Steve Dickson + +diff --git a/support/export/hostname.c b/support/export/hostname.c +index 169baa5..7a44d42 100644 +--- a/support/export/hostname.c ++++ b/support/export/hostname.c +@@ -134,6 +134,8 @@ host_pton(const char *paddr) + break; + } + return ai; ++ case EAI_NONAME: ++ break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", + __func__, paddr, errno); diff --git a/SOURCES/nfs-utils-1.3.0-libmount-umount-verbose.patch b/SOURCES/nfs-utils-1.3.0-libmount-umount-verbose.patch new file mode 100644 index 0000000..89cd24c --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-libmount-umount-verbose.patch @@ -0,0 +1,45 @@ +diff -up nfs-utils-1.3.0/utils/mount/mount_libmount.c.orig nfs-utils-1.3.0/utils/mount/mount_libmount.c +--- nfs-utils-1.3.0/utils/mount/mount_libmount.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mount/mount_libmount.c 2014-10-24 09:46:11.158190704 -0400 +@@ -173,7 +173,7 @@ static int umount_main(struct libmnt_con + { + 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' }, +@@ -200,6 +200,8 @@ static int umount_main(struct libmnt_con + return EX_USAGE; + } + ++ verbose = mnt_context_is_verbose(cxt); ++ + if (optind < argc) + spec = argv[optind++]; + +@@ -227,6 +229,10 @@ static int umount_main(struct libmnt_con + 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)) { +@@ -262,6 +268,12 @@ static int umount_main(struct libmnt_con + } + 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/SOURCES/nfs-utils-1.3.0-mount-addressfailed.patch b/SOURCES/nfs-utils-1.3.0-mount-addressfailed.patch new file mode 100644 index 0000000..8fe08e9 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-addressfailed.patch @@ -0,0 +1,30 @@ +diff -up nfs-utils-1.3.0/utils/nfsd/nfssvc.c.orig nfs-utils-1.3.0/utils/nfsd/nfssvc.c +--- nfs-utils-1.3.0/utils/nfsd/nfssvc.c.orig 2017-10-05 11:34:15.701116069 -0400 ++++ nfs-utils-1.3.0/utils/nfsd/nfssvc.c 2017-10-05 11:35:36.493684800 -0400 +@@ -112,7 +112,7 @@ static int + nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port) + { + int fd, on = 1, fac = L_ERROR; +- int sockfd = -1, rc = 0; ++ int sockfd = -1, rc = 0, bounded = 0; + struct addrinfo *addrhead = NULL, *addr; + char *proto, *family; + +@@ -234,6 +234,8 @@ nfssvc_setfds(const struct addrinfo *hin + rc = errno; + goto error; + } ++ bounded++; ++ + close(fd); + close(sockfd); + sockfd = fd = -1; +@@ -246,7 +248,7 @@ error: + close(sockfd); + if (addrhead) + freeaddrinfo(addrhead); +- return rc; ++ return (bounded ? 0 : rc); + } + + int diff --git a/SOURCES/nfs-utils-1.3.0-mount-default-v42.patch b/SOURCES/nfs-utils-1.3.0-mount-default-v42.patch new file mode 100644 index 0000000..c715ccc --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-default-v42.patch @@ -0,0 +1,590 @@ +diff --git a/configure.ac b/configure.ac +index 56f7f3e..802fd58 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -172,10 +172,12 @@ AC_ARG_ENABLE(ipv6, + if test "$enable_mount" = yes; then + AC_ARG_ENABLE(mountconfig, + [AC_HELP_STRING([--enable-mountconfig], +- [enable mount to use a configuration file])], ++ [enable mount to use a configuration file @<:@default=yes@:>@])], + mountconfig=$enableval, +- mountconfig=no) +- if test "$enable_mountconfig" = yes; then ++ mountconfig=yes) ++ if test "$enable_mountconfig" = no; then ++ enable_mountconfig= ++ else + AC_DEFINE(MOUNT_CONFIG, 1, + [Define this if you want mount to read a configuration file]) + AC_ARG_WITH(mountfile, +@@ -187,8 +189,6 @@ if test "$enable_mount" = yes; then + AC_SUBST(mountfile) + AC_DEFINE_UNQUOTED(MOUNTOPTS_CONFFILE, "$mountfile", + [This defines the location of the NFS mount configuration file]) +- else +- enable_mountconfig= + fi + AC_SUBST(enable_mountconfig) + AM_CONDITIONAL(MOUNT_CONFIG, [test "$enable_mountconfig" = "yes"]) +diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c +index 39d3741..0a4cc04 100644 +--- a/utils/mount/configfile.c ++++ b/utils/mount/configfile.c +@@ -228,37 +228,8 @@ void free_all(void) + free(entry); + } + } +-static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL}; +-static int +-check_vers(char *mopt, char *field) +-{ +- int i, found=0; +- +- /* +- * First check to see if the config setting is one +- * of the many version settings +- */ +- for (i=0; versions[i]; i++) { +- if (strcasestr(field, versions[i]) != NULL) { +- found++; +- break; +- } +- } +- if (!found) +- return 0; +- /* +- * It appears the version is being set, now see +- * if the version appears on the command +- */ +- for (i=0; versions[i]; i++) { +- if (strcasestr(mopt, versions[i]) != NULL) +- return 1; +- } +- +- return 0; +-} + +-unsigned long config_default_vers; ++struct nfs_version config_default_vers; + unsigned long config_default_proto; + extern sa_family_t config_default_family; + +@@ -331,11 +302,6 @@ conf_parse_mntopts(char *section, char *arg, char *opts) + snprintf(buf, BUFSIZ, "%s=", node->field); + if (opts && strcasestr(opts, buf) != NULL) + continue; +- /* +- * Protocol verions can be set in a number of ways +- */ +- if (opts && check_vers(opts, node->field)) +- continue; + + if (lookup_entry(node->field) != NULL) + continue; +diff --git a/utils/mount/network.c b/utils/mount/network.c +index 515249b..088caa1 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -92,9 +92,6 @@ static const char *nfs_version_opttbl[] = { + "v4", + "vers", + "nfsvers", +- "v4.0", +- "v4.1", +- "v4.2", + NULL, + }; + +@@ -1249,71 +1246,69 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) + * or FALSE if the option was specified with an invalid value. + */ + int +-nfs_nfs_version(struct mount_options *options, unsigned long *version) ++nfs_nfs_version(struct mount_options *options, struct nfs_version *version) + { +- long tmp; ++ char *version_key, *version_val, *cptr; ++ int i, found = 0; + +- switch (po_rightmost(options, nfs_version_opttbl)) { +- case 0: /* v2 */ +- *version = 2; +- return 1; +- case 1: /* v3 */ +- *version = 3; +- return 1; +- case 2: /* v4 */ +- *version = 4; +- return 1; +- case 3: /* vers */ +- switch (po_get_numeric(options, "vers", &tmp)) { +- case PO_FOUND: +- if (tmp >= 2 && tmp <= 4) { +- *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"), +- progname); +- return 0; +- case PO_BAD_VALUE: +- nfs_error(_("%s: invalid value for 'vers=' option"), +- progname); +- return 0; +- } +- case 4: /* nfsvers */ +- switch (po_get_numeric(options, "nfsvers", &tmp)) { +- case PO_FOUND: +- if (tmp >= 2 && tmp <= 4) { +- *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"), +- progname); +- return 0; +- case PO_BAD_VALUE: +- nfs_error(_("%s: invalid value for 'nfsvers=' option"), +- progname); +- return 0; ++ version->v_mode = V_DEFAULT; ++ ++ for (i = 0; nfs_version_opttbl[i]; i++) { ++ if (po_contains_prefix(options, nfs_version_opttbl[i], ++ &version_key) == PO_FOUND) { ++ found++; ++ break; + } +- case 5: /* v4.0 */ +- case 6: /* v4.1 */ +- case 7: /* v4.2 */ +- *version = 4; ++ } ++ ++ if (!found) + return 1; ++ ++ if (i <= 2 ) { ++ /* v2, v3, v4 */ ++ version_val = version_key + 1; ++ version->v_mode = V_SPECIFIC; ++ } else if (i > 2 ) { ++ /* vers=, nfsvers= */ ++ version_val = po_get(options, version_key); + } + +- /* +- * NFS version wasn't specified. The pmap version value +- * will be filled in later by an rpcbind query in this case. +- */ +- *version = 0; ++ if (!version_val) ++ goto ret_error; ++ ++ if (!(version->major = strtol(version_val, &cptr, 10))) ++ goto ret_error; ++ ++ if (version->major < 4) ++ version->v_mode = V_SPECIFIC; ++ ++ if (*cptr == '.') { ++ version_val = ++cptr; ++ if (!(version->minor = strtol(version_val, &cptr, 10)) && cptr == version_val) ++ goto ret_error; ++ version->v_mode = V_SPECIFIC; ++ } else if (version->major > 3 && *cptr == '\0') ++ version->v_mode = V_GENERAL; ++ ++ if (*cptr != '\0') ++ goto ret_error; ++ + return 1; ++ ++ret_error: ++ if (i <= 2 ) { ++ nfs_error(_("%s: parsing error on 'v' option"), ++ progname); ++ } else if (i == 3 ) { ++ nfs_error(_("%s: parsing error on 'vers=' option"), ++ progname); ++ } else if (i == 4) { ++ nfs_error(_("%s: parsing error on 'nfsvers=' option"), ++ progname); ++ } ++ version->v_mode = V_PARSE_ERR; ++ errno = EINVAL; ++ return 0; + } + + /* +@@ -1632,10 +1627,13 @@ out_err: + int nfs_options2pmap(struct mount_options *options, + struct pmap *nfs_pmap, struct pmap *mnt_pmap) + { ++ struct nfs_version version; ++ + if (!nfs_nfs_program(options, &nfs_pmap->pm_prog)) + return 0; +- if (!nfs_nfs_version(options, &nfs_pmap->pm_vers)) ++ if (!nfs_nfs_version(options, &version)) + return 0; ++ nfs_pmap->pm_vers = version.major; + if (!nfs_nfs_protocol(options, &nfs_pmap->pm_prot)) + return 0; + if (!nfs_nfs_port(options, &nfs_pmap->pm_port)) +diff --git a/utils/mount/network.h b/utils/mount/network.h +index d7636d7..9cc5dec 100644 +--- a/utils/mount/network.h ++++ b/utils/mount/network.h +@@ -57,9 +57,22 @@ int clnt_ping(struct sockaddr_in *, const unsigned long, + + struct mount_options; + ++enum { ++ V_DEFAULT = 0, ++ V_GENERAL, ++ V_SPECIFIC, ++ V_PARSE_ERR, ++}; ++ ++struct nfs_version { ++ unsigned long major; ++ unsigned long minor; ++ int v_mode; ++}; ++ + int nfs_nfs_proto_family(struct mount_options *options, sa_family_t *family); + int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family); +-int nfs_nfs_version(struct mount_options *options, unsigned long *version); ++int nfs_nfs_version(struct mount_options *options, struct nfs_version *version); + int nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol); + + int nfs_options2pmap(struct mount_options *, +diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c +index 3538d88..de284f2 100644 +--- a/utils/mount/nfsumount.c ++++ b/utils/mount/nfsumount.c +@@ -179,10 +179,10 @@ static int nfs_umount_is_vers4(const struct mntentchn *mc) + + options = po_split(pmc->m.mnt_opts); + if (options != NULL) { +- unsigned long version; ++ struct nfs_version version; + int rc = nfs_nfs_version(options, &version); + po_destroy(options); +- if (rc && version == 4) ++ if (rc && version.major == 4) + goto out_nfs4; + } + +diff --git a/utils/mount/parse_opt.c b/utils/mount/parse_opt.c +index 75a0daa..7ba61c4 100644 +--- a/utils/mount/parse_opt.c ++++ b/utils/mount/parse_opt.c +@@ -391,7 +391,7 @@ po_return_t po_append(struct mount_options *options, char *str) + } + + /** +- * po_contains - check for presense of an option in a group ++ * po_contains - check for presence of an option in a group + * @options: pointer to mount options + * @keyword: pointer to a C string containing option keyword for which to search + * +@@ -410,6 +410,30 @@ po_found_t po_contains(struct mount_options *options, char *keyword) + } + + /** ++ * po_contains_prefix - check for presence of an option matching a prefix ++ * @options: pointer to mount options ++ * @prefix: pointer to prefix to match against a keyword ++ * @keyword: pointer to a C string containing the option keyword if found ++ * ++ * On success, *keyword contains the pointer of the matching option's keyword. ++ */ ++po_found_t po_contains_prefix(struct mount_options *options, ++ const char *prefix, char **keyword) ++{ ++ struct mount_option *option; ++ ++ if (options && prefix) { ++ for (option = options->head; option; option = option->next) ++ if (strncmp(option->keyword, prefix, strlen(prefix)) == 0) { ++ *keyword = option->keyword; ++ return PO_FOUND; ++ } ++ } ++ ++ return PO_NOT_FOUND; ++} ++ ++/** + * po_get - return the value of the rightmost instance of an option + * @options: pointer to mount options + * @keyword: pointer to a C string containing option keyword for which to search +diff --git a/utils/mount/parse_opt.h b/utils/mount/parse_opt.h +index 5037207..0745e0f 100644 +--- a/utils/mount/parse_opt.h ++++ b/utils/mount/parse_opt.h +@@ -45,6 +45,8 @@ po_return_t po_join(struct mount_options *, char **); + + po_return_t po_append(struct mount_options *, char *); + po_found_t po_contains(struct mount_options *, char *); ++po_found_t po_contains_prefix(struct mount_options *options, ++ const char *prefix, char **keyword); + char * po_get(struct mount_options *, char *); + po_found_t po_get_numeric(struct mount_options *, + char *, long *); +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index 5d80ed7..207a476 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -88,30 +88,50 @@ struct nfsmount_info { + struct mount_options *options; /* parsed mount options */ + char **extra_opts; /* string for /etc/mtab */ + +- unsigned long version; /* NFS version */ ++ struct nfs_version version; /* NFS version */ + int flags, /* MS_ flags */ + fake, /* actually do the mount? */ + child; /* forked bg child? */ + }; + +-#ifdef MOUNT_CONFIG +-static void nfs_default_version(struct nfsmount_info *mi); + + static void nfs_default_version(struct nfsmount_info *mi) + { +- extern unsigned long config_default_vers; ++#ifdef MOUNT_CONFIG ++ extern struct nfs_version config_default_vers; + /* + * Use the default value set in the config file when + * the version has not been explicitly set. + */ +- if (mi->version == 0 && config_default_vers) { +- if (config_default_vers < 4) +- mi->version = config_default_vers; ++ if (config_default_vers.v_mode == V_PARSE_ERR) { ++ mi->version.v_mode = V_PARSE_ERR; ++ return; + } +-} +-#else +-inline void nfs_default_version(__attribute__ ((unused)) struct nfsmount_info *mi) {} ++ ++ if (mi->version.v_mode == V_GENERAL && ++ config_default_vers.v_mode == V_DEFAULT) { ++ mi->version.v_mode = V_SPECIFIC; ++ return; ++ } ++ ++ if (mi->version.v_mode == V_DEFAULT && ++ config_default_vers.v_mode != V_DEFAULT) { ++ mi->version.major = config_default_vers.major; ++ mi->version.minor = config_default_vers.minor; ++ return; ++ } ++ ++ if (mi->version.v_mode == V_GENERAL && ++ config_default_vers.v_mode != V_DEFAULT) { ++ if (mi->version.major == config_default_vers.major) ++ mi->version.minor = config_default_vers.minor; ++ return; ++ } ++ + #endif /* MOUNT_CONFIG */ ++ mi->version.major = 4; ++ mi->version.minor = 2; ++} + + /* + * Obtain a retry timeout value based on the value of the "retry=" option. +@@ -300,7 +320,7 @@ static int nfs_set_version(struct nfsmount_info *mi) + return 0; + + if (strncmp(mi->type, "nfs4", 4) == 0) +- mi->version = 4; ++ mi->version.major = 4; + + /* + * Before 2.6.32, the kernel NFS client didn't +@@ -308,28 +328,44 @@ static int nfs_set_version(struct nfsmount_info *mi) + * 4 cannot be included when autonegotiating + * while running on those kernels. + */ +- if (mi->version == 0 && +- linux_version_code() <= MAKE_VERSION(2, 6, 31)) +- mi->version = 3; ++ if (mi->version.v_mode == V_DEFAULT && ++ linux_version_code() <= MAKE_VERSION(2, 6, 31)) { ++ mi->version.major = 3; ++ mi->version.v_mode = V_SPECIFIC; ++ } + + /* + * If we still don't know, check for version-specific + * mount options. + */ +- if (mi->version == 0) { ++ if (mi->version.v_mode == V_DEFAULT) { + if (po_contains(mi->options, "mounthost") || + po_contains(mi->options, "mountaddr") || + po_contains(mi->options, "mountvers") || +- po_contains(mi->options, "mountproto")) +- mi->version = 3; ++ po_contains(mi->options, "mountproto")) { ++ mi->version.major = 3; ++ mi->version.v_mode = V_SPECIFIC; ++ } + } + + /* + * If enabled, see if the default version was + * set in the config file + */ +- nfs_default_version(mi); +- ++ if (mi->version.v_mode != V_SPECIFIC) { ++ nfs_default_version(mi); ++ /* ++ * If the version was not specifically set, it will ++ * be set by autonegotiation later, so remove it now: ++ */ ++ po_remove_all(mi->options, "v4"); ++ po_remove_all(mi->options, "vers"); ++ po_remove_all(mi->options, "nfsvers"); ++ } ++ ++ if (mi->version.v_mode == V_PARSE_ERR) ++ return 0; ++ + return 1; + } + +@@ -693,6 +729,7 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi, + { + struct mount_options *options = po_dup(mi->options); + int result = 0; ++ char version_opt[16]; + char *extra_opts = NULL; + + if (!options) { +@@ -700,20 +737,24 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi, + return result; + } + +- if (mi->version == 0) { +- if (po_contains(options, "mounthost") || +- po_contains(options, "mountaddr") || +- po_contains(options, "mountvers") || +- po_contains(options, "mountproto")) { +- /* +- * Since these mountd options are set assume version 3 +- * is wanted so error out with EPROTONOSUPPORT so the +- * protocol negation starts with v3. +- */ +- errno = EPROTONOSUPPORT; +- goto out_fail; +- } +- if (po_append(options, "vers=4") == PO_FAILED) { ++ if (po_contains(options, "mounthost") || ++ po_contains(options, "mountaddr") || ++ po_contains(options, "mountvers") || ++ po_contains(options, "mountproto")) { ++ /* ++ * Since these mountd options are set assume version 3 ++ * is wanted so error out with EPROTONOSUPPORT so the ++ * protocol negation starts with v3. ++ */ ++ errno = EPROTONOSUPPORT; ++ goto out_fail; ++ } ++ ++ if (mi->version.v_mode != V_SPECIFIC) { ++ snprintf(version_opt, sizeof(version_opt) - 1, ++ "vers=%lu.%lu", mi->version.major, mi->version.minor); ++ ++ if (po_append(options, version_opt) == PO_FAILED) { + errno = EINVAL; + goto out_fail; + } +@@ -801,14 +842,28 @@ static int nfs_autonegotiate(struct nfsmount_info *mi) + int result; + + result = nfs_try_mount_v4(mi); ++check_result: + if (result) + return result; + +-check_errno: + switch (errno) { + case EPROTONOSUPPORT: + /* A clear indication that the server or our +- * client does not support NFS version 4. */ ++ * client does not support NFS version 4 and minor */ ++ case EINVAL: ++ /* A less clear indication that our client ++ * does not support NFSv4 minor version. */ ++ if (mi->version.v_mode == V_GENERAL && ++ mi->version.minor == 0) ++ return result; ++ if (mi->version.v_mode != V_SPECIFIC) { ++ if (mi->version.minor > 0) { ++ mi->version.minor--; ++ result = nfs_try_mount_v4(mi); ++ goto check_result; ++ } ++ } ++ + goto fall_back; + case ENOENT: + /* Legacy Linux servers don't export an NFS +@@ -827,7 +882,7 @@ check_errno: + /* v4 server seems to be registered now. */ + result = nfs_try_mount_v4(mi); + if (result == 0 && errno != ECONNREFUSED) +- goto check_errno; ++ goto check_result; + } + return result; + default: +@@ -848,19 +903,19 @@ static int nfs_try_mount(struct nfsmount_info *mi) + { + int result = 0; + +- switch (mi->version) { +- case 0: +- result = nfs_autonegotiate(mi); +- break; +- case 2: +- case 3: +- result = nfs_try_mount_v3v2(mi, FALSE); +- break; +- case 4: +- result = nfs_try_mount_v4(mi); +- break; +- default: +- errno = EIO; ++ switch (mi->version.major) { ++ case 2: ++ case 3: ++ result = nfs_try_mount_v3v2(mi, FALSE); ++ break; ++ case 4: ++ if (mi->version.v_mode != V_SPECIFIC) ++ result = nfs_autonegotiate(mi); ++ else ++ result = nfs_try_mount_v4(mi); ++ break; ++ default: ++ errno = EIO; + } + + return result; diff --git a/SOURCES/nfs-utils-1.3.0-mount-eacces.patch b/SOURCES/nfs-utils-1.3.0-mount-eacces.patch new file mode 100644 index 0000000..a9cfdb0 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-eacces.patch @@ -0,0 +1,13 @@ +diff -up nfs-utils-1.3.0/utils/mount/stropts.c.orig nfs-utils-1.3.0/utils/mount/stropts.c +--- nfs-utils-1.3.0/utils/mount/stropts.c.orig 2017-09-19 11:25:13.889948761 -0400 ++++ nfs-utils-1.3.0/utils/mount/stropts.c 2017-09-19 11:29:44.454636781 -0400 +@@ -851,6 +851,9 @@ check_result: + case EINVAL: + /* A less clear indication that our client + * does not support NFSv4 minor version. */ ++ case EACCES: ++ /* An unclear indication that the server ++ * may not support NFSv4 minor version. */ + if (mi->version.v_mode != V_SPECIFIC) { + if (mi->version.minor > 0) { + mi->version.minor--; diff --git a/SOURCES/nfs-utils-1.3.0-mount-explicit-rback.patch b/SOURCES/nfs-utils-1.3.0-mount-explicit-rback.patch new file mode 100644 index 0000000..4e1241b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-explicit-rback.patch @@ -0,0 +1,46 @@ +diff -up nfs-utils-1.3.0/utils/mount/stropts.c.orig nfs-utils-1.3.0/utils/mount/stropts.c +--- nfs-utils-1.3.0/utils/mount/stropts.c.orig 2017-06-01 11:24:19.925018714 -0400 ++++ nfs-utils-1.3.0/utils/mount/stropts.c 2017-06-01 11:25:20.033023121 -0400 +@@ -313,9 +313,10 @@ static int nfs_set_version(struct nfsmou + if (!nfs_nfs_version(mi->options, &mi->version)) + return 0; + +- if (strncmp(mi->type, "nfs4", 4) == 0) ++ if (strncmp(mi->type, "nfs4", 4) == 0) { + mi->version.major = 4; +- ++ mi->version.v_mode = V_GENERAL; ++ } + /* + * Before 2.6.32, the kernel NFS client didn't + * support "-t nfs vers=4" mounts, so NFS version +@@ -856,9 +857,6 @@ check_result: + case EINVAL: + /* A less clear indication that our client + * does not support NFSv4 minor version. */ +- if (mi->version.v_mode == V_GENERAL && +- mi->version.minor == 0) +- return result; + if (mi->version.v_mode != V_SPECIFIC) { + if (mi->version.minor > 0) { + mi->version.minor--; +@@ -880,6 +878,9 @@ check_result: + /* UDP-Only servers won't support v4, but maybe it + * just isn't ready yet. So try v3, but double-check + * with rpcbind for v4. */ ++ if (mi->version.v_mode == V_GENERAL) ++ /* Mustn't try v2,v3 */ ++ return result; + result = nfs_try_mount_v3v2(mi, TRUE); + if (result == 0 && errno == EAGAIN) { + /* v4 server seems to be registered now. */ +@@ -893,6 +894,9 @@ check_result: + } + + fall_back: ++ if (mi->version.v_mode == V_GENERAL) ++ /* v2,3 fallback not allowed */ ++ return result; + return nfs_try_mount_v3v2(mi, FALSE); + } + diff --git a/SOURCES/nfs-utils-1.3.0-mount-nfs-types.patch b/SOURCES/nfs-utils-1.3.0-mount-nfs-types.patch new file mode 100644 index 0000000..f2d199c --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-nfs-types.patch @@ -0,0 +1,43 @@ +commit d1f6583a5ff32711a1da1d4a13a29a5700f63504 +Author: Ben Hutchings +Date: Thu Apr 2 11:43:33 2015 -0400 + + mount.nfs.man, nfs.man: Update distinction between fstypes + + From: Ben Hutchings + + this is a resync of the man page updates in the Debian + package with mainline nfs-utils. + + Acked-By: J. Bruce Fields + Signed-off-by: Steve Dickson + +diff --git a/utils/mount/mount.nfs.man b/utils/mount/mount.nfs.man +index 1a4561b..15a82d5 100644 +--- a/utils/mount/mount.nfs.man ++++ b/utils/mount/mount.nfs.man +@@ -15,16 +15,20 @@ is meant to be used by the + .BR mount (8) + command for mounting NFS shares. This subcommand, however, can also be used as a standalone command with limited functionality. + +-.BR mount.nfs4 +-is used for mounting NFSv4 file system, while +-.BR mount.nfs +-is used to mount NFS file systems versions 3 or 2. + .I remotetarget + is a server share usually in the form of + .BR servername:/path/to/share. + .I dir + is the directory on which the file system is to be mounted. + ++Under Linux 2.6.32 and later kernel versions, ++.BR mount.nfs ++can mount all NFS file system versions. Under earlier Linux kernel versions, ++.BR mount.nfs4 ++must be used for mounting NFSv4 file systems while ++.BR mount.nfs ++must be used for NFSv3 and v2. ++ + .SH OPTIONS + .TP + .BI "\-r" diff --git a/SOURCES/nfs-utils-1.3.0-mount-prognotreg.patch b/SOURCES/nfs-utils-1.3.0-mount-prognotreg.patch new file mode 100644 index 0000000..6fea773 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-prognotreg.patch @@ -0,0 +1,82 @@ +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index bdd7c24..89b90a1 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -931,19 +931,45 @@ static int nfs_try_mount(struct nfsmount_info *mi) + * failed so far, but fail immediately if there is a local + * error (like a bad mount option). + * +- * ESTALE is also a temporary error because some servers +- * return ESTALE when a share is temporarily offline. ++ * If there is a remote error, like ESTALE or RPC_PROGNOTREGISTERED ++ * then it is probably permanent, but there is a small chance ++ * the it is temporary can we caught the server at an awkward ++ * time during start-up. So require that we see three of those ++ * before treating them as permanent. ++ * For ECONNREFUSED, wait a bit longer as there is often a longer ++ * gap between the network being ready and the NFS server starting. + * + * Returns 1 if we should fail immediately, or 0 if we + * should retry. + */ + static int nfs_is_permanent_error(int error) + { ++ static int prev_error; ++ static int rpt_cnt; ++ ++ if (error == prev_error) ++ rpt_cnt += 1; ++ else ++ rpt_cnt = 1; ++ prev_error = error; ++ + switch (error) { + case ESTALE: +- case ETIMEDOUT: ++ case EOPNOTSUPP: /* aka RPC_PROGNOTREGISTERED */ ++ /* If two in a row, assume permanent */ ++ return rpt_cnt >= 3; + case ECONNREFUSED: ++ /* Like the above, this can be temporary during a ++ * small window. However it is typically a larger ++ * window than for the others, and we have historically ++ * treated this as a temporary (i.e. long timeout) ++ * error with no complaints, so continue to treat ++ * it as temporary. ++ */ ++ return 0; /* temporary */ ++ case ETIMEDOUT: + case EHOSTUNREACH: ++ case EAGAIN: + return 0; /* temporary */ + default: + return 1; /* permanent */ +@@ -987,7 +1013,7 @@ static int nfsmount_fg(struct nfsmount_info *mi) + if (secs > 10) + secs = 10; + } +- }; ++ } + + mount_error(mi->spec, mi->node, errno); + return EX_FAIL; +@@ -1005,8 +1031,7 @@ static int nfsmount_parent(struct nfsmount_info *mi) + if (nfs_try_mount(mi)) + return EX_SUCCESS; + +- /* retry background mounts when the server is not up */ +- if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) { ++ if (nfs_is_permanent_error(errno)) { + mount_error(mi->spec, mi->node, errno); + return EX_FAIL; + } +@@ -1041,8 +1066,7 @@ static int nfsmount_child(struct nfsmount_info *mi) + if (nfs_try_mount(mi)) + return EX_SUCCESS; + +- /* retry background mounts when the server is not up */ +- if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) ++ if (nfs_is_permanent_error(errno)) + break; + + if (time(NULL) > timeout) diff --git a/SOURCES/nfs-utils-1.3.0-mount-remount.patch b/SOURCES/nfs-utils-1.3.0-mount-remount.patch new file mode 100644 index 0000000..da8b190 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-remount.patch @@ -0,0 +1,48 @@ +diff -up nfs-utils-1.3.0/utils/mount/stropts.c.orig nfs-utils-1.3.0/utils/mount/stropts.c +--- nfs-utils-1.3.0/utils/mount/stropts.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mount/stropts.c 2016-04-28 11:18:25.876793000 -0400 +@@ -352,13 +352,26 @@ static int nfs_validate_options(struct n + if (!nfs_nfs_proto_family(mi->options, &family)) + return 0; + +- hint.ai_family = (int)family; +- error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); +- if (error != 0) { +- nfs_error(_("%s: Failed to resolve server %s: %s"), +- progname, mi->hostname, gai_strerror(error)); +- mi->address = NULL; +- return 0; ++ /* ++ * A remount is not going to be able to change the server's address, ++ * nor should we try to resolve another address for the server as we ++ * may end up with a different address. ++ */ ++ if (mi->flags & MS_REMOUNT) { ++ po_remove_all(mi->options, "addr"); ++ } else { ++ hint.ai_family = (int)family; ++ error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); ++ if (error != 0) { ++ nfs_error(_("%s: Failed to resolve server %s: %s"), ++ progname, mi->hostname, gai_strerror(error)); ++ mi->address = NULL; ++ return 0; ++ } ++ ++ if (!nfs_append_addr_option(mi->address->ai_addr, ++ mi->address->ai_addrlen, mi->options)) ++ return 0; + } + + if (!nfs_set_version(mi)) +@@ -367,10 +380,6 @@ static int nfs_validate_options(struct n + if (!nfs_append_sloppy_option(mi->options)) + return 0; + +- if (!nfs_append_addr_option(mi->address->ai_addr, +- mi->address->ai_addrlen, mi->options)) +- return 0; +- + return 1; + } + diff --git a/SOURCES/nfs-utils-1.3.0-mount-restore-econn.patch b/SOURCES/nfs-utils-1.3.0-mount-restore-econn.patch new file mode 100644 index 0000000..8247a1a --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-restore-econn.patch @@ -0,0 +1,156 @@ +diff --git a/utils/mount/network.c b/utils/mount/network.c +index 751f9b8..b2e4374 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -33,11 +33,13 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -802,6 +804,7 @@ int start_statd(void) + pid_t pid = fork(); + switch (pid) { + case 0: /* child */ ++ setgroups(0, NULL); + setgid(0); + setuid(0); + execle(START_STATD, START_STATD, NULL, envp); +@@ -1112,6 +1115,7 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen, + .sin6_addr = IN6ADDR_ANY_INIT, + }; + int sock, result = 0; ++ int val; + + sock = socket(sap->sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) +@@ -1123,6 +1127,9 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen, + goto out; + break; + case AF_INET6: ++ /* Make sure the call-back address is public/permanent */ ++ val = IPV6_PREFER_SRC_PUBLIC; ++ setsockopt(sock, SOL_IPV6, IPV6_ADDR_PREFERENCES, &val, sizeof(val)); + if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0) + goto out; + break; +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index fc68d41..57e932f 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -91,6 +91,7 @@ struct nfsmount_info { + *type; /* "nfs" or "nfs4" */ + char *hostname; /* server's hostname */ + struct addrinfo *address; /* server's addresses */ ++ sa_family_t family; /* Address family */ + + struct mount_options *options; /* parsed mount options */ + char **extra_opts; /* string for /etc/mtab */ +@@ -388,39 +389,19 @@ static int nfs_set_version(struct nfsmount_info *mi) + */ + static int nfs_validate_options(struct nfsmount_info *mi) + { +- struct addrinfo hint = { +- .ai_protocol = (int)IPPROTO_UDP, +- }; +- sa_family_t family; +- int error; +- + if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) + return 0; + +- if (!nfs_nfs_proto_family(mi->options, &family)) ++ if (!nfs_nfs_proto_family(mi->options, &mi->family)) + return 0; + + /* + * A remount is not going to be able to change the server's address, + * nor should we try to resolve another address for the server as we + * may end up with a different address. ++ * A non-remount will set 'addr' from ->hostname + */ +- if (mi->flags & MS_REMOUNT) { +- po_remove_all(mi->options, "addr"); +- } else { +- hint.ai_family = (int)family; +- error = getaddrinfo(mi->hostname, NULL, &hint, &mi->address); +- if (error != 0) { +- nfs_error(_("%s: Failed to resolve server %s: %s"), +- progname, mi->hostname, gai_strerror(error)); +- mi->address = NULL; +- return 0; +- } +- +- if (!nfs_append_addr_option(mi->address->ai_addr, +- mi->address->ai_addrlen, mi->options)) +- return 0; +- } ++ po_remove_all(mi->options, "addr"); + + if (!nfs_set_version(mi)) + return 0; +@@ -900,7 +881,10 @@ check_result: + result = nfs_try_mount_v4(mi); + if (result == 0 && errno != ECONNREFUSED) + goto check_result; +- } ++ } else if (result == 0) ++ /* Restore original errno with v3 failures */ ++ errno = ECONNREFUSED; ++ + return result; + default: + return result; +@@ -923,6 +907,32 @@ static int nfs_try_mount(struct nfsmount_info *mi) + { + int result = 0; + ++ if (mi->address == NULL) { ++ struct addrinfo hint = { ++ .ai_protocol = (int)IPPROTO_UDP, ++ }; ++ int error; ++ struct addrinfo *address; ++ ++ hint.ai_family = (int)mi->family; ++ error = getaddrinfo(mi->hostname, NULL, &hint, &address); ++ if (error != 0) { ++ if (error == EAI_AGAIN) ++ errno = EAGAIN; ++ else { ++ nfs_error(_("%s: Failed to resolve server %s: %s"), ++ progname, mi->hostname, gai_strerror(error)); ++ errno = EALREADY; ++ } ++ return 0; ++ } ++ ++ if (!nfs_append_addr_option(address->ai_addr, ++ address->ai_addrlen, mi->options)) ++ return 0; ++ mi->address = address; ++ } ++ + switch (mi->version.major) { + case 2: + case 3: +@@ -1018,10 +1028,8 @@ static int nfsmount_fg(struct nfsmount_info *mi) + if (nfs_is_permanent_error(errno)) + break; + +- if (time(NULL) > timeout) { +- errno = ETIMEDOUT; ++ if (time(NULL) > timeout) + break; +- } + + if (errno != ETIMEDOUT) { + if (sleep(secs)) diff --git a/SOURCES/nfs-utils-1.3.0-mount-uninit-structs.patch b/SOURCES/nfs-utils-1.3.0-mount-uninit-structs.patch new file mode 100644 index 0000000..1cfbc67 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-uninit-structs.patch @@ -0,0 +1,100 @@ +commit 0712b5507866d6b3c900623eb1f81fffaec80ae2 +Author: Jianhong Yin +Date: Thu Feb 2 06:21:15 2017 -0500 + + mount: fix mount fail that caused by uninitialized struct + + From: "Jianhong.Yin" + + recent changes of utils/mount cause a regression mount fail: + https://bugzilla.redhat.com/show_bug.cgi?id=1415024 + can not reproduce it on x86_64(gcc on x86_64 might do struct + initialize by default, I'm not sure). but it can be reproduced + always on platform ppc64le aarch64. + + Signed-off-by: Jianhong Yin + Signed-off-by: Steve Dickson + +diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c +index 4d18d35..77125f1 100644 +--- a/utils/gssd/gssd.c ++++ b/utils/gssd/gssd.c +@@ -87,6 +87,7 @@ int root_uses_machine_creds = 1; + unsigned int context_timeout = 0; + unsigned int rpc_timeout = 5; + char *preferred_realm = NULL; ++char *ccachedir = NULL; + /* Avoid DNS reverse lookups on server names */ + static bool avoid_dns = true; + int thread_started = false; +@@ -837,18 +838,9 @@ usage(char *progname) + exit(1); + } + +-int +-main(int argc, char *argv[]) ++inline static void ++read_gss_conf(void) + { +- int fg = 0; +- int verbosity = 0; +- int rpc_verbosity = 0; +- int opt; +- int i; +- extern char *optarg; +- char *progname; +- char *ccachedir = NULL; +- struct event sighup_ev; + char *s; + + conf_init(); +@@ -877,6 +869,22 @@ main(int argc, char *argv[]) + if (s) + preferred_realm = s; + ++} ++ ++int ++main(int argc, char *argv[]) ++{ ++ int fg = 0; ++ int verbosity = 0; ++ int rpc_verbosity = 0; ++ int opt; ++ int i; ++ extern char *optarg; ++ char *progname; ++ struct event sighup_ev; ++ ++ read_gss_conf(); ++ + while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { + switch (opt) { + case 'f': +diff --git a/utils/mount/network.c b/utils/mount/network.c +index 7dceb2d..d1c8fec 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -1638,6 +1638,7 @@ int nfs_options2pmap(struct mount_options *options, + struct pmap *nfs_pmap, struct pmap *mnt_pmap) + { + struct nfs_version version; ++ memset(&version, 0, sizeof(version)); + + if (!nfs_nfs_program(options, &nfs_pmap->pm_prog)) + return 0; +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index 387d734..a9ff95d 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -517,6 +517,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4) + unsigned long protocol; + struct pmap mnt_pmap; + ++ /* initialize structs */ ++ memset(&nfs_pmap, 0, sizeof(struct pmap)); ++ memset(&mnt_pmap, 0, sizeof(struct pmap)); ++ + /* + * Version and transport negotiation is not required + * and does not work for RDMA mounts. diff --git a/SOURCES/nfs-utils-1.3.0-mount-usage.patch b/SOURCES/nfs-utils-1.3.0-mount-usage.patch new file mode 100644 index 0000000..4240fb5 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-usage.patch @@ -0,0 +1,19 @@ +diff -up nfs-utils-1.3.0/utils/mount/mount_libmount.c.orig nfs-utils-1.3.0/utils/mount/mount_libmount.c +--- nfs-utils-1.3.0/utils/mount/mount_libmount.c.orig 2016-06-08 09:48:19.446035537 -0400 ++++ nfs-utils-1.3.0/utils/mount/mount_libmount.c 2016-06-08 09:57:58.389518986 -0400 +@@ -207,6 +207,7 @@ static int umount_main(struct libmnt_con + + if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) { + nfs_error(_("%s: no mount point provided"), progname); ++ umount_usage(); + return EX_USAGE; + } + +@@ -328,6 +329,7 @@ static int mount_main(struct libmnt_cont + + if (!mount_point) { + nfs_error(_("%s: no mount point provided"), progname); ++ mount_usage(); + goto err; + } + if (!spec) { diff --git a/SOURCES/nfs-utils-1.3.0-mount-use-minor-default.patch b/SOURCES/nfs-utils-1.3.0-mount-use-minor-default.patch new file mode 100644 index 0000000..fb68b7e --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-use-minor-default.patch @@ -0,0 +1,89 @@ +diff -up nfs-utils-1.3.0/nfs.conf.orig nfs-utils-1.3.0/nfs.conf +--- nfs-utils-1.3.0/nfs.conf.orig 2017-06-19 11:15:31.661716122 -0400 ++++ nfs-utils-1.3.0/nfs.conf 2017-06-19 11:15:51.945058695 -0400 +@@ -66,6 +66,3 @@ + # outgoing-port= + # outgoing-addr= + # lift-grace=y +-# +-#[svcgssd] +-# principal= +diff -up nfs-utils-1.3.0/utils/mount/stropts.c.orig nfs-utils-1.3.0/utils/mount/stropts.c +--- nfs-utils-1.3.0/utils/mount/stropts.c.orig 2017-06-19 11:15:31.667716223 -0400 ++++ nfs-utils-1.3.0/utils/mount/stropts.c 2017-06-19 11:25:53.000204600 -0400 +@@ -73,6 +73,13 @@ + #define NFS_DEF_BG_TIMEOUT_MINUTES (10000u) + #endif + ++#ifndef NFS_DEFAULT_MAJOR ++#define NFS_DEFAULT_MAJOR 4 ++#endif ++#ifndef NFS_DEFAULT_MINOR ++#define NFS_DEFAULT_MINOR 1 ++#endif ++ + extern int nfs_mount_data_version; + extern char *progname; + extern int verbose; +@@ -111,20 +118,28 @@ static void nfs_default_version(struct n + if (mi->version.v_mode == V_DEFAULT && + config_default_vers.v_mode != V_DEFAULT) { + mi->version.major = config_default_vers.major; +- mi->version.minor = config_default_vers.minor; ++ if (config_default_vers.v_mode == V_SPECIFIC) ++ mi->version.minor = config_default_vers.minor; ++ else ++ mi->version.minor = NFS_DEFAULT_MINOR; + return; + } + + if (mi->version.v_mode == V_GENERAL) { + if (config_default_vers.v_mode != V_DEFAULT && +- mi->version.major == config_default_vers.major) +- mi->version.minor = config_default_vers.minor; ++ mi->version.major == config_default_vers.major) { ++ if (config_default_vers.v_mode == V_SPECIFIC) ++ mi->version.minor = config_default_vers.minor; ++ else ++ mi->version.minor = NFS_DEFAULT_MINOR; ++ } else ++ mi->version.minor = NFS_DEFAULT_MINOR; + return; + } + + #endif /* MOUNT_CONFIG */ +- mi->version.major = 4; +- mi->version.minor = 1; ++ mi->version.major = NFS_DEFAULT_MAJOR; ++ mi->version.minor = NFS_DEFAULT_MINOR; + } + + /* +@@ -314,7 +329,9 @@ static int nfs_set_version(struct nfsmou + return 0; + + if (strncmp(mi->type, "nfs4", 4) == 0) { +- mi->version.major = 4; ++ /* Set to default values */ ++ mi->version.major = NFS_DEFAULT_MAJOR; ++ mi->version.minor = NFS_DEFAULT_MINOR; + mi->version.v_mode = V_GENERAL; + } + /* +@@ -750,13 +767,9 @@ static int nfs_do_mount_v4(struct nfsmou + } + + if (mi->version.v_mode != V_SPECIFIC) { +- if (mi->version.v_mode == V_GENERAL) +- snprintf(version_opt, sizeof(version_opt) - 1, +- "vers=%lu", mi->version.major); +- else +- snprintf(version_opt, sizeof(version_opt) - 1, +- "vers=%lu.%lu", mi->version.major, +- mi->version.minor); ++ snprintf(version_opt, sizeof(version_opt) - 1, ++ "vers=%lu.%lu", mi->version.major, ++ mi->version.minor); + + if (po_append(options, version_opt) == PO_FAILED) { + errno = EINVAL; diff --git a/SOURCES/nfs-utils-1.3.0-mount-v41.patch b/SOURCES/nfs-utils-1.3.0-mount-v41.patch new file mode 100644 index 0000000..73c38d0 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-v41.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/utils/mount/stropts.c.orig nfs-utils-1.3.0/utils/mount/stropts.c +--- nfs-utils-1.3.0/utils/mount/stropts.c.orig 2017-03-28 11:13:30.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mount/stropts.c 2017-03-28 11:24:11.000000000 -0400 +@@ -124,7 +124,7 @@ static void nfs_default_version(struct n + + #endif /* MOUNT_CONFIG */ + mi->version.major = 4; +- mi->version.minor = 2; ++ mi->version.minor = 1; + } + + /* diff --git a/SOURCES/nfs-utils-1.3.0-mount-v4arg-fix.patch b/SOURCES/nfs-utils-1.3.0-mount-v4arg-fix.patch new file mode 100644 index 0000000..65c2a5b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mount-v4arg-fix.patch @@ -0,0 +1,45 @@ +diff -up nfs-utils-1.3.0/utils/mount/stropts.c.orig nfs-utils-1.3.0/utils/mount/stropts.c +--- nfs-utils-1.3.0/utils/mount/stropts.c.orig 2016-12-18 10:59:32.526389233 -0500 ++++ nfs-utils-1.3.0/utils/mount/stropts.c 2016-12-18 11:02:17.564900647 -0500 +@@ -108,12 +108,6 @@ static void nfs_default_version(struct n + return; + } + +- if (mi->version.v_mode == V_GENERAL && +- config_default_vers.v_mode == V_DEFAULT) { +- mi->version.v_mode = V_SPECIFIC; +- return; +- } +- + if (mi->version.v_mode == V_DEFAULT && + config_default_vers.v_mode != V_DEFAULT) { + mi->version.major = config_default_vers.major; +@@ -121,9 +115,9 @@ static void nfs_default_version(struct n + return; + } + +- if (mi->version.v_mode == V_GENERAL && +- config_default_vers.v_mode != V_DEFAULT) { +- if (mi->version.major == config_default_vers.major) ++ if (mi->version.v_mode == V_GENERAL) { ++ if (config_default_vers.v_mode != V_DEFAULT && ++ mi->version.major == config_default_vers.major) + mi->version.minor = config_default_vers.minor; + return; + } +@@ -751,8 +745,13 @@ static int nfs_do_mount_v4(struct nfsmou + } + + if (mi->version.v_mode != V_SPECIFIC) { +- snprintf(version_opt, sizeof(version_opt) - 1, +- "vers=%lu.%lu", mi->version.major, mi->version.minor); ++ if (mi->version.v_mode == V_GENERAL) ++ snprintf(version_opt, sizeof(version_opt) - 1, ++ "vers=%lu", mi->version.major); ++ else ++ snprintf(version_opt, sizeof(version_opt) - 1, ++ "vers=%lu.%lu", mi->version.major, ++ mi->version.minor); + + if (po_append(options, version_opt) == PO_FAILED) { + errno = EINVAL; diff --git a/SOURCES/nfs-utils-1.3.0-mountd-dos.patch b/SOURCES/nfs-utils-1.3.0-mountd-dos.patch new file mode 100644 index 0000000..93a19ed --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-dos.patch @@ -0,0 +1,168 @@ +diff -up nfs-utils-1.3.0/support/include/nfslib.h.orig nfs-utils-1.3.0/support/include/nfslib.h +--- nfs-utils-1.3.0/support/include/nfslib.h.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/include/nfslib.h 2014-11-14 11:16:06.785633197 -0500 +@@ -174,6 +174,7 @@ 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 -up nfs-utils-1.3.0/support/nfs/rpcmisc.c.orig nfs-utils-1.3.0/support/nfs/rpcmisc.c +--- nfs-utils-1.3.0/support/nfs/rpcmisc.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/rpcmisc.c 2014-11-14 11:16:06.785633197 -0500 +@@ -104,7 +104,7 @@ makesock(int port, int proto) + return -1; + } + +- return sock; ++ return svcsock_nonblock(sock); + } + + void +diff -up nfs-utils-1.3.0/support/nfs/svc_create.c.orig nfs-utils-1.3.0/support/nfs/svc_create.c +--- nfs-utils-1.3.0/support/nfs/svc_create.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/svc_create.c 2014-11-14 11:16:06.785633197 -0500 +@@ -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 *n + "(%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 * + 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 + 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 + */ + (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 -up nfs-utils-1.3.0/support/nfs/svc_socket.c.orig nfs-utils-1.3.0/support/nfs/svc_socket.c +--- nfs-utils-1.3.0/support/nfs/svc_socket.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/svc_socket.c 2014-11-14 11:16:06.785633197 -0500 +@@ -67,6 +67,39 @@ int getservport(u_long number, const cha + 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) + { +@@ -104,38 +137,7 @@ svc_socket (u_long number, int type, int + 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/SOURCES/nfs-utils-1.3.0-mountd-filedes.patch b/SOURCES/nfs-utils-1.3.0-mountd-filedes.patch new file mode 100644 index 0000000..0e05ddb --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-filedes.patch @@ -0,0 +1,633 @@ +diff -up nfs-utils-1.3.0/utils/mountd/cache.c.orig nfs-utils-1.3.0/utils/mountd/cache.c +--- nfs-utils-1.3.0/utils/mountd/cache.c.orig 2017-01-06 09:31:53.155412013 -0500 ++++ nfs-utils-1.3.0/utils/mountd/cache.c 2017-01-06 09:50:52.438190388 -0500 +@@ -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; +@@ -715,12 +728,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 +@@ -729,20 +743,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; + +@@ -752,20 +767,20 @@ static void write_fsloc(FILE *f, struct + 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; + +@@ -776,45 +791,52 @@ static void write_secinfo(FILE *f, struc + 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 * +@@ -1164,27 +1186,27 @@ static struct exportent *lookup_junction + 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 +@@ -1192,26 +1214,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; +- +- xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf); +- +- cp = lbuf; +- dom = malloc(strlen(cp)); +- path = malloc(strlen(cp)); ++ 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'", buf); ++ ++ 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(); +@@ -1225,14 +1249,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); +@@ -1244,15 +1268,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; +@@ -1269,11 +1292,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); + } + } + +@@ -1285,8 +1304,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); + } + } + +@@ -1299,11 +1318,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; +@@ -1316,14 +1335,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" +@@ -1364,13 +1383,13 @@ static int cache_export_ent(char *domain + 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; + } + +@@ -1381,27 +1400,25 @@ static int cache_export_ent(char *domain + */ + 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; + ++ 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; + +- 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; ++ return cache_export_ent(buf, sizeof(buf), exp->m_client->m_hostname, &exp->m_export, path); + } + + /** +@@ -1420,27 +1437,33 @@ int cache_export(nfs_export *exp, char * + 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; + +- if (!f) +- f = fopen("/proc/fs/nfs/filehandle", "r+"); +- if (!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; ++ } ++ ++ 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/SOURCES/nfs-utils-1.3.0-mountd-manpage-P.patch b/SOURCES/nfs-utils-1.3.0-mountd-manpage-P.patch new file mode 100644 index 0000000..8e56689 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-manpage-P.patch @@ -0,0 +1,27 @@ +commit d0f9df9761d5fc63327fcaa0bc4515e739ca6f0e +Author: Yongcheng Yang +Date: Wed Mar 16 12:15:32 2016 -0400 + + mountd.man: Update to change -P option as an alias for -p + + From: Yongcheng Yang + + Signed-off-by: Yongcheng Yang + Signed-off-by: Steve Dickson + +diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man +index 7c5bfbe..66e3bba 100644 +--- a/utils/mountd/mountd.man ++++ b/utils/mountd/mountd.man +@@ -115,10 +115,7 @@ must be invoked with the option + .B \-n " or " \-\-no-tcp + Don't advertise TCP for mount. + .TP +-.B \-P +-Ignored (compatibility with unfsd??). +-.TP +-.B \-p num " or " \-\-port num ++.B \-p num " or " \-P num " or " \-\-port num + Specifies the port number used for RPC listener sockets. + If this option is not specified, + .B rpc.mountd diff --git a/SOURCES/nfs-utils-1.3.0-mountd-manpage-args.patch b/SOURCES/nfs-utils-1.3.0-mountd-manpage-args.patch new file mode 100644 index 0000000..b9eadc1 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-manpage-args.patch @@ -0,0 +1,57 @@ +diff -up nfs-utils-1.3.0/utils/mountd/mountd.man.start nfs-utils-1.3.0/utils/mountd/mountd.man +--- nfs-utils-1.3.0/utils/mountd/mountd.man.start 2015-07-14 15:42:00.817994335 -0400 ++++ nfs-utils-1.3.0/utils/mountd/mountd.man 2015-07-14 15:42:17.347273962 -0400 +@@ -86,7 +86,7 @@ Turn on debugging. Valid kinds are: all, + .B \-F " or " \-\-foreground + Run in foreground (do not daemonize) + .TP +-.B \-f " or " \-\-exports-file ++.B \-f export-file " or " \-\-exports-file export-file + This option specifies the exports file, listing the clients that this + server is prepared to serve and parameters to apply to each + such mount (see +@@ -101,7 +101,7 @@ Display usage message. + Set the limit of the number of open file descriptors to num. The + default is to leave the limit unchanged. + .TP +-.B \-N " or " \-\-no-nfs-version ++.B \-N mountd-version " or " \-\-no-nfs-version mountd-version + This option can be used to request that + .B rpc.mountd + do not offer certain versions of NFS. The current version of +@@ -118,7 +118,7 @@ Don't advertise TCP for mount. + .B \-P + Ignored (compatibility with unfsd??). + .TP +-.B \-p " or " \-\-port num ++.B \-p num " or " \-\-port num + Specifies the port number used for RPC listener sockets. + If this option is not specified, + .B rpc.mountd +@@ -132,7 +132,7 @@ This option can be used to fix the port + listeners when NFS MOUNT requests must traverse a firewall + between clients and servers. + .TP +-.B \-H " or " \-\-ha-callout prog ++.B \-H " prog or " \-\-ha-callout prog + Specify a high availability callout program. + This program receives callouts for all MOUNT and UNMOUNT requests. + This allows +@@ -174,7 +174,7 @@ to perform a reverse lookup on each IP a + Enabling this can have a substantial negative effect on performance + in some situations. + .TP +-.BR "\-t N" " or " "\-\-num\-threads=N" ++.BR "\-t N" " or " "\-\-num\-threads=N " or " \-\-num\-threads N " + This option specifies the number of worker threads that rpc.mountd + spawns. The default is 1 thread, which is probably enough. More + threads are usually only needed for NFS servers which need to handle +@@ -184,7 +184,7 @@ your DNS server is slow or unreliable. + .B \-u " or " \-\-no-udp + Don't advertise UDP for mounting + .TP +-.B \-V " or " \-\-nfs-version ++.B \-V version " or " \-\-nfs-version version + This option can be used to request that + .B rpc.mountd + offer certain versions of NFS. The current version of diff --git a/SOURCES/nfs-utils-1.3.0-mountd-manpage-netconfig.patch b/SOURCES/nfs-utils-1.3.0-mountd-manpage-netconfig.patch new file mode 100644 index 0000000..23c1313 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-manpage-netconfig.patch @@ -0,0 +1,39 @@ +diff -up nfs-utils-1.3.0/utils/mount/mount.nfs.man.orig nfs-utils-1.3.0/utils/mount/mount.nfs.man +--- nfs-utils-1.3.0/utils/mount/mount.nfs.man.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mount/mount.nfs.man 2015-06-25 10:27:18.001345779 -0400 +@@ -76,10 +76,13 @@ file system table + .TP + .I /etc/mtab + table of mounted file systems +- ++.TP ++.I /etc/nfsmount.conf ++Configuration file for NFS mounts + .PD + .SH "SEE ALSO" + .BR nfs (5), ++.BR nfsmount.conf (5), + .BR mount (8), + + .SH "AUTHOR" +diff -up nfs-utils-1.3.0/utils/mount/nfs.man.orig nfs-utils-1.3.0/utils/mount/nfs.man +--- nfs-utils-1.3.0/utils/mount/nfs.man.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mount/nfs.man 2015-06-25 10:27:18.001345779 -0400 +@@ -1706,6 +1706,9 @@ with the mount options already saved on + .TP 1.5i + .I /etc/fstab + file system table ++.TP 1.5i ++.I /etc/nfsmount.conf ++Configuration file for NFS mounts + .SH BUGS + Before 2.4.7, the Linux NFS client did not support NFS over TCP. + .P +@@ -1735,6 +1738,7 @@ such as security negotiation, server ref + .BR mount.nfs (5), + .BR umount.nfs (5), + .BR exports (5), ++.BR nfsmount.conf (5), + .BR netconfig (5), + .BR ipv6 (7), + .BR nfsd (8), diff --git a/SOURCES/nfs-utils-1.3.0-mountd-netgroups.patch b/SOURCES/nfs-utils-1.3.0-mountd-netgroups.patch new file mode 100644 index 0000000..fbab37c --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-netgroups.patch @@ -0,0 +1,31 @@ +diff -up nfs-utils-1.3.0/support/export/client.c.save nfs-utils-1.3.0/support/export/client.c +--- nfs-utils-1.3.0/support/export/client.c.save 2016-06-07 14:02:11.244677000 -0400 ++++ nfs-utils-1.3.0/support/export/client.c 2016-06-07 14:03:11.380193000 -0400 +@@ -635,7 +635,7 @@ check_netgroup(const nfs_client *clp, co + const char *netgroup = clp->m_hostname + 1; + struct addrinfo *tmp = NULL; + struct hostent *hp; +- char *dot, *hname; ++ char *dot, *hname, *ip; + int i, match; + + match = 0; +@@ -682,6 +682,18 @@ check_netgroup(const nfs_client *clp, co + } + } + ++ /* check whether the IP itself is in the netgroup */ ++ ip = calloc(INET6_ADDRSTRLEN, 1); ++ if (inet_ntop(ai->ai_family, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, INET6_ADDRSTRLEN) == ip) { ++ if (innetgr(netgroup, ip, NULL, NULL)) { ++ free(hname); ++ hname = ip; ++ match = 1; ++ goto out; ++ } ++ } ++ free(ip); ++ + /* Okay, strip off the domain (if we have one) */ + dot = strchr(hname, '.'); + if (dot == NULL) diff --git a/SOURCES/nfs-utils-1.3.0-mountd-root.patch b/SOURCES/nfs-utils-1.3.0-mountd-root.patch new file mode 100644 index 0000000..eae1f14 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-root.patch @@ -0,0 +1,157 @@ +commit 710a492fda68092a02d6360d7a185f6a4dcaea85 +Author: NeilBrown +Date: Thu Feb 26 14:10:35 2015 -0500 + + exports.man: improve documentation of 'nohide' and 'crossmnt' + + - note that 'nohide' is irrelevant for NFSv4 + - note that children on a 'crossmnt' filesystem cannot be unexported + - note that 'nocrossmnt' is a valid option, but probably not useful. + + Signed-off-by: NeilBrown + Signed-off-by: Steve Dickson + +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index 59358e6..9309246 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 + +commit b7341b19d62481504f1820414159009535d37809 +Author: NeilBrown +Date: Wed Feb 25 16:47:56 2015 -0500 + + mountd: fix next_mnt handling for "/" + + If the (exported) path passed to next_mnt() is simply "/", next_mnt() + will not report any children, as none start with "/" followed by a '/'. + So make a special case for strlen(p)==1. In that case, return all + children. + + This gives correct handling if only "/" is exported. + + Signed-off-by: NeilBrown + Signed-off-by: Steve Dickson + +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index 1430aee..23af4a9 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -365,7 +365,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] != '/')) + ; + +commit 7e27d4a542bf97e0ddc1036010e1b2d218a01c2b +Author: Vivek Trivedi +Date: Wed Sep 16 11:14:03 2015 -0400 + + mountd: fix mount issue due to comparison with uninitialized uuid + + Fix mount issue due to comparison of uninitialized variable + u(uuid) with parsed->fhuuid when uuid_by_path return 0. + + /tmp/usb + 192.168.1.0/16(ro,no_root_squash,no_subtree_check,fsid=0) + /tmp/usb/sda1 192.168.1.0/16(ro,no_root_squash,no_subtree_check) + /tmp/usb/sdb1 192.168.1.0/16(ro,no_root_squash,no_subtree_check) + + mount -t nfs -o nolock,nfsvers=3 192.168.1.2:/tmp/usb/sda1 /tmp/sda1 + mount -t nfs -o nolock,nfsvers=3 192.168.1.2:/tmp/usb/sdb1 /tmp/sdb1 + + results in below mountd error: + mountd: /tmp/usb and /tmp/usb/sdb1 have same filehandle for + 192.168.1.0/16, using first + + when uuid_by_path returned 0, by chance, garbage value of u was same as + parsed->fhuuid(of sdb1), and comparison of these resulted in above + error. + + Signed-off-by: Vivek Trivedi + Reviewed-by: Amit Sahrawat + Signed-off-by: Steve Dickson + +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index 9a1bb27..1430aee 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -547,18 +547,17 @@ static bool match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path) + if (!is_mountpoint(path)) + return false; + check_uuid: +- if (exp->m_export.e_uuid) ++ if (exp->m_export.e_uuid) { + get_uuid(exp->m_export.e_uuid, parsed->uuidlen, u); ++ if (memcmp(u, parsed->fhuuid, parsed->uuidlen) == 0) ++ return true; ++ } + else + for (type = 0; + uuid_by_path(path, type, parsed->uuidlen, u); + type++) + if (memcmp(u, parsed->fhuuid, parsed->uuidlen) == 0) + return true; +- +- if (memcmp(u, parsed->fhuuid, parsed->uuidlen) != 0) +- return false; +- return true; + } + /* Well, unreachable, actually: */ + return false; diff --git a/SOURCES/nfs-utils-1.3.0-mountd-start-statd-path.patch b/SOURCES/nfs-utils-1.3.0-mountd-start-statd-path.patch new file mode 100644 index 0000000..47194f7 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-start-statd-path.patch @@ -0,0 +1,29 @@ +commit edbbbe099bf4d4902f29d087239d6d159ac2187d +Author: Kinglong Mee +Date: Fri Apr 25 10:28:47 2014 -0400 + + systemd: add PATH for finding systemctl + + The 1.3.0 release adds a call to systemctl fails for it's in /usr/bin. + + [root@localhost nfs-utils]# start-statd + /usr/sbin/start-statd: line 9: systemctl: command not found + Statd service already running! + + Reported-by: Allan Duncan + Signed-off-by: Kinglong Mee + Signed-off-by: Steve Dickson + +diff --git a/utils/statd/start-statd b/utils/statd/start-statd +index cde3583..8ac3798 100644 +--- a/utils/statd/start-statd ++++ b/utils/statd/start-statd +@@ -4,7 +4,7 @@ + # /var/run/rpc.statd.pid). + # It should run statd with whatever flags are apropriate for this + # site. +-PATH=/sbin:/usr/sbin ++PATH="/sbin:/usr/sbin:/bin:/usr/bin" + if systemctl start statd.service + then : + else diff --git a/SOURCES/nfs-utils-1.3.0-mountd-usage-error.patch b/SOURCES/nfs-utils-1.3.0-mountd-usage-error.patch new file mode 100644 index 0000000..d127a5c --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-usage-error.patch @@ -0,0 +1,25 @@ +commit 6ec0d58fbff7c1a814a21cf8c7fe0ef5106a04c1 +Author: Steve Dickson +Date: Wed Jan 20 14:16:08 2016 -0500 + + mountd: print an error message when no versions are specified + + Signed-off-by: Steve Dickson + +diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c +index 8aca181..b584afc 100644 +--- a/utils/mountd/mountd.c ++++ b/utils/mountd/mountd.c +@@ -794,9 +794,10 @@ main(int argc, char **argv) + } + + /* No more arguments allowed. */ +- if (optind != argc || !version_any()) ++ if (optind != argc || !version_any()) { ++ fprintf(stderr, "%s: No protocol versions specified!\n", progname); + usage(progname, 1); +- ++ } + if (chdir(state_dir)) { + fprintf(stderr, "%s: chdir(%s) failed: %s\n", + progname, state_dir, strerror(errno)); diff --git a/SOURCES/nfs-utils-1.3.0-mountd-usage.patch b/SOURCES/nfs-utils-1.3.0-mountd-usage.patch new file mode 100644 index 0000000..2d674ca --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-usage.patch @@ -0,0 +1,14 @@ +diff -up nfs-utils-1.3.0/utils/mountd/mountd.c.orig nfs-utils-1.3.0/utils/mountd/mountd.c +--- nfs-utils-1.3.0/utils/mountd/mountd.c.orig 2016-02-11 09:57:51.376317000 -0500 ++++ nfs-utils-1.3.0/utils/mountd/mountd.c 2016-02-11 10:02:54.377956000 -0500 +@@ -911,7 +911,8 @@ usage(const char *prog, int n) + " [-o num|--descriptors num] [-f exports-file|--exports-file=file]\n" + " [-p|--port port] [-V version|--nfs-version version]\n" + " [-N version|--no-nfs-version version] [-n|--no-tcp]\n" +-" [-H ha-callout-prog] [-s|--state-directory-path path]\n" +-" [-g|--manage-gids] [-t num|--num-threads=num] [-u|--no-udp]\n", prog); ++" [-H prog |--ha-callout prog] [-r |--reverse-lookup]\n" ++" [-s|--state-directory-path path] [-g|--manage-gids]\n" ++" [-t num|--num-threads=num] [-u|--no-udp]\n", prog); + exit(n); + } diff --git a/SOURCES/nfs-utils-1.3.0-mountd-v4root-sec.patch b/SOURCES/nfs-utils-1.3.0-mountd-v4root-sec.patch new file mode 100644 index 0000000..7485825 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountd-v4root-sec.patch @@ -0,0 +1,102 @@ +commit 4a1ad4aa3028d26d830d9a9003ff9e3337b0e0d5 +Author: Scott Mayhew +Date: Thu Apr 2 11:15:15 2015 -0400 + + mountd: Enable all auth flavors on pseudofs exports + + With the current mountd code it's possible to craft exports in such a + manner that clients will be unable to mount exports that they *should* + be able to mount. + + Consider the following example: + + /foo *(rw,insecure,no_root_squash,sec=krb5p) + /bar client.example.com(rw,insecure,no_root_squash) + + Initially, client.example.com will be able to mount the /foo export + using sec=krb5p, but attempts to mount /bar using sec=sys will return + EPERM. Once the nfsd.export cache entry expires, client.example.com + will then be able to mount /bar using sec=sys but attempts to mount /foo + using sec=krb5p will return EPERM. + + The reason this happens is because the initial nfsd.export cache entry + is actually pre-populated by nfsd_fh(), which is the handler for the + nfsd.fh cache, while later cache requests (once the initial entry + expires) are handled by nfsd_export(). These functions have slightly + different logic in how they select a v4root export from the cache -- + nfsd_fh() takes last matching v4root export it finds, while + nfsd_export() (actually lookup_export()) takes the first. Either way + it's wrong because the client should be able to mount both exports. + + Both rfc3503bis and rfc5661 say: + + A common and convenient practice, unless strong security requirements + dictate otherwise, is to make the entire pseudo file system + accessible by all of the valid security mechanisms. + + ...so lets do that. + + Acked-by: J. Bruce Fields + Signed-off-by: Scott Mayhew + Signed-off-by: Steve Dickson + +diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c +index 34d098a..429ebb8 100644 +--- a/utils/mountd/v4root.c ++++ b/utils/mountd/v4root.c +@@ -26,6 +26,7 @@ + #include "nfslib.h" + #include "misc.h" + #include "v4root.h" ++#include "pseudoflavors.h" + + int v4root_needed; + +@@ -56,22 +57,22 @@ static nfs_export pseudo_root = { + }; + + static void +-set_pseudofs_security(struct exportent *pseudo, struct exportent *source) ++set_pseudofs_security(struct exportent *pseudo, int flags) + { +- struct sec_entry *se; ++ struct flav_info *flav; + int i; + +- if (source->e_flags & NFSEXP_INSECURE_PORT) ++ if (flags & NFSEXP_INSECURE_PORT) + pseudo->e_flags |= NFSEXP_INSECURE_PORT; +- if ((source->e_flags & NFSEXP_ROOTSQUASH) == 0) ++ if ((flags & NFSEXP_ROOTSQUASH) == 0) + pseudo->e_flags &= ~NFSEXP_ROOTSQUASH; +- for (se = source->e_secinfo; se->flav; se++) { ++ for (flav = flav_map; flav < flav_map + flav_map_size; flav++) { + struct sec_entry *new; + +- i = secinfo_addflavor(se->flav, pseudo); ++ i = secinfo_addflavor(flav, pseudo); + new = &pseudo->e_secinfo[i]; + +- if (se->flags & NFSEXP_INSECURE_PORT) ++ if (flags & NFSEXP_INSECURE_PORT) + new->flags |= NFSEXP_INSECURE_PORT; + } + } +@@ -91,7 +92,7 @@ v4root_create(char *path, nfs_export *export) + strncpy(eep.e_path, path, sizeof(eep.e_path)); + if (strcmp(path, "/") != 0) + eep.e_flags &= ~NFSEXP_FSID; +- set_pseudofs_security(&eep, curexp); ++ set_pseudofs_security(&eep, curexp->e_flags); + exp = export_create(&eep, 0); + if (exp == NULL) + return NULL; +@@ -139,7 +140,7 @@ pseudofs_update(char *hostname, char *path, nfs_export *source) + return 0; + } + /* Update an existing V4ROOT export: */ +- set_pseudofs_security(&exp->m_export, &source->m_export); ++ set_pseudofs_security(&exp->m_export, source->m_export.e_flags); + return 0; + } + diff --git a/SOURCES/nfs-utils-1.3.0-mountstats-iostats.patch b/SOURCES/nfs-utils-1.3.0-mountstats-iostats.patch new file mode 100644 index 0000000..8efd060 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountstats-iostats.patch @@ -0,0 +1,15 @@ +diff -up nfs-utils-1.3.0/tools/mountstats/mountstats.py.orig nfs-utils-1.3.0/tools/mountstats/mountstats.py +--- nfs-utils-1.3.0/tools/mountstats/mountstats.py.orig 2017-04-08 15:23:53.524215286 -0400 ++++ nfs-utils-1.3.0/tools/mountstats/mountstats.py 2017-04-08 15:30:45.862043179 -0400 +@@ -565,7 +565,10 @@ class DeviceData: + for the nfsstat command. + """ + for op in new_stats.__rpc_data['ops']: +- self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) ++ try: ++ self.__rpc_data[op] = list(map(add, self.__rpc_data[op], new_stats.__rpc_data[op])) ++ except KeyError: ++ continue + + def __print_rpc_op_stats(self, op, sample_time): + """Print generic stats for one RPC op diff --git a/SOURCES/nfs-utils-1.3.0-mountstats-manpage-fix.patch b/SOURCES/nfs-utils-1.3.0-mountstats-manpage-fix.patch new file mode 100644 index 0000000..fc2fbb8 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountstats-manpage-fix.patch @@ -0,0 +1,36 @@ +commit f2efa15ef8c083926791195ed1037fd47a5e4e41 +Author: Scott Mayhew +Date: Wed Sep 16 11:19:41 2015 -0400 + + mountstats.man: Remove a few bogus .R macros + + These have no effect on the rendering of the man page, but they do cause + the following error if you try to pipe or redirect the output: + + `R' is a string (producing the registered sign), not a macro. + + Signed-off-by: Scott Mayhew + Signed-off-by: Steve Dickson + +diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man +index bfc4c46..a55130b 100644 +--- a/tools/mountstats/mountstats.man ++++ b/tools/mountstats/mountstats.man +@@ -13,13 +13,13 @@ mountstats \- Displays various NFS client per-mount statistics + .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 diff --git a/SOURCES/nfs-utils-1.3.0-mountstats-manpage-fix2.patch b/SOURCES/nfs-utils-1.3.0-mountstats-manpage-fix2.patch new file mode 100644 index 0000000..bc4fa4a --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountstats-manpage-fix2.patch @@ -0,0 +1,21 @@ +commit 8c7d7fe5577b059130d472d4145a09cf9d4a7ea2 +Author: Steve Dickson +Date: Mon Aug 10 09:58:01 2015 -0400 + + mountstats.man: fixed typo in man page + + Signed-off-by: Steve Dickson + +diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man +index a9df1e4..bfc4c46 100644 +--- a/tools/mountstats/mountstats.man ++++ b/tools/mountstats/mountstats.man +@@ -115,7 +115,7 @@ options. + 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 ++.BR \-S | \-\-since + options. + .P + .IP "\fIcount\fP" diff --git a/SOURCES/nfs-utils-1.3.0-mountstats-pnfs.patch b/SOURCES/nfs-utils-1.3.0-mountstats-pnfs.patch new file mode 100644 index 0000000..3f5f860 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountstats-pnfs.patch @@ -0,0 +1,26 @@ +commit 3e2ab78a2cfbc2d11c31ced8d3f538d5aae757f1 +Author: Scott Mayhew +Date: Thu Sep 22 13:33:33 2016 -0400 + + mountstats: add pNFS READs and WRITEs + + These counters are already in /proc/self/mountstats but the mountstats + program doesn't display them. + + Signed-off-by: Scott Mayhew + Signed-off-by: Steve Dickson + Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1377740 + +diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py +index 4ca4bc4..88ccdae 100644 +--- a/tools/mountstats/mountstats.py ++++ b/tools/mountstats/mountstats.py +@@ -412,6 +412,8 @@ class DeviceData: + print(' short reads: %d short writes: %d' % \ + (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])) + print(' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']) ++ print(' pNFS READs: %d' % self.__nfs_data['pnfsreads']) ++ print(' pNFS WRITEs: %d' % self.__nfs_data['pnfswrites']) + + def display_nfs_bytes(self): + """Pretty-print the NFS event counters diff --git a/SOURCES/nfs-utils-1.3.0-mountstats-update.patch b/SOURCES/nfs-utils-1.3.0-mountstats-update.patch new file mode 100644 index 0000000..247b0aa --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-mountstats-update.patch @@ -0,0 +1,1326 @@ +diff -up nfs-utils-1.3.0/tools/mountstats/mountstats.man.good nfs-utils-1.3.0/tools/mountstats/mountstats.man +--- nfs-utils-1.3.0/tools/mountstats/mountstats.man.good 2015-07-30 15:19:01.718000115 -0400 ++++ nfs-utils-1.3.0/tools/mountstats/mountstats.man 2015-07-30 15:19:35.430613995 -0400 +@@ -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 -up nfs-utils-1.3.0/tools/mountstats/mountstats.py.good nfs-utils-1.3.0/tools/mountstats/mountstats.py +--- nfs-utils-1.3.0/tools/mountstats/mountstats.py.good 2015-07-30 15:16:42.390463126 -0400 ++++ nfs-utils-1.3.0/tools/mountstats/mountstats.py 2015-07-30 15:16:20.391062604 -0400 +@@ -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') ++ print(format('ops/s', '>16') + format('rpc bklog', '>16')) ++ print(format((sends / sample_time), '>16.3f'), end='') ++ print(format(backlog, '>16.3f')) ++ print() + +- # 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') ++ self.__print_rpc_op_stats('READ', sample_time) ++ self.__print_rpc_op_stats('WRITE', sample_time) ++ sys.stdout.flush() + +-def parse_stats_file(filename): ++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 = file(filename) ++ f.seek(0) + for line in f.readlines(): + words = line.split() + if len(words) == 0: +@@ -385,132 +661,156 @@ 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 ++ mountstats = parse_stats_file(args.infile) ++ mountpoints = [os.path.normpath(mp) for mp in args.mountpoints] + +- 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 +- +- 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 1 + +- 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() ++ return 0 + +- 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 = [os.path.normpath(mp) for mp in 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) +- return ++ # 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 1 + +- 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() +- else: +- stats.display_nfs_options() +- stats.display_nfs_bytes() +- stats.display_rpc_generic_stats() +- 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() +- +-def nfsstat_command(): +- print_nfsstat_help(prog) ++ if not args.since: ++ acc_stats = stats ++ elif args.since and mp not in old_mountstats: ++ acc_stats = stats ++ else: ++ old_stats = DeviceData() ++ old_stats.parse_stats(old_mountstats[mp]) ++ acc_stats = stats.compare_iostats(old_stats) + +-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 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) ++ ++ 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)) ++ ++ 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() ++ return 0 + + 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 +818,28 @@ def print_iostat_summary(old, new, devic + 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 ++ mountstats = parse_stats_file(args.infile) ++ devices = [os.path.normpath(mp) for mp in args.mountpoints] + +- if arg in ['-v', '--version', 'version']: +- print('%s version %s' % (sys.argv[0], Mountstats_version)) +- return +- +- if arg == sys.argv[0]: +- continue +- +- 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(): +@@ -572,45 +849,148 @@ def iostat_command(): + devices += [device] + if len(devices) == 0: + print('No NFS mount points were found') +- return ++ return 1 + +- 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') +- +-# +-# Main +-# +-prog = os.path.basename(sys.argv[0]) ++ time.sleep(args.interval) ++ sample_time = args.interval ++ mountstats = parse_stats_file(args.infile) ++ ++ args.infile.close() ++ if args.since: ++ args.since.close() ++ return 0 ++ ++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 (KeyboardInterrupt, RuntimeError): + sys.exit(1) ++except IOError: ++ pass + +-sys.exit(0) +diff -up nfs-utils-1.3.0/tools/nfs-iostat/nfs-iostat.py.good nfs-utils-1.3.0/tools/nfs-iostat/nfs-iostat.py +--- nfs-utils-1.3.0/tools/nfs-iostat/nfs-iostat.py.good 2015-07-30 15:16:58.774761466 -0400 ++++ nfs-utils-1.3.0/tools/nfs-iostat/nfs-iostat.py 2015-07-30 15:16:20.391062604 -0400 +@@ -213,7 +213,8 @@ 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'] diff --git a/SOURCES/nfs-utils-1.3.0-nfs-conf.patch b/SOURCES/nfs-utils-1.3.0-nfs-conf.patch new file mode 100644 index 0000000..0252267 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfs-conf.patch @@ -0,0 +1,1892 @@ +diff -up nfs-utils-1.3.0/configure.ac.orig nfs-utils-1.3.0/configure.ac +--- nfs-utils-1.3.0/configure.ac.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/configure.ac 2017-03-28 13:43:53.000000000 -0400 +@@ -23,6 +23,12 @@ AC_ARG_WITH(statedir, + statedir=$withval, + statedir=/var/lib/nfs) + AC_SUBST(statedir) ++AC_ARG_WITH(nfsconfig, ++ [AC_HELP_STRING([--with-nfsconfig=/config/file], ++ [use general config file /config/file @<:@default=/etc/nfs.conf@:>@])], ++ nfsconfig=$withval, ++ nfsconfig=/etc/nfs.conf) ++ AC_SUBST(nfsconfig) + AC_ARG_WITH(statdpath, + [AC_HELP_STRING([--with-statdpath=/foo], + [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])], +@@ -442,6 +448,7 @@ dnl Export some path names to config.h + dnl ************************************************************* + AC_DEFINE_UNQUOTED(NFS_STATEDIR, "$statedir", [This defines the location of the NFS state files. Warning: this must match definitions in config.mk!]) + AC_DEFINE_UNQUOTED(NSM_DEFAULT_STATEDIR, "$statdpath", [Define this to the pathname where statd keeps its state file]) ++AC_DEFINE_UNQUOTED(NFS_CONFFILE, "$nfsconfig", [This defines the location of NFS daemon config file]) + + if test "x$cross_compiling" = "xno"; then + CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD-"$CFLAGS"} +diff -up nfs-utils-1.3.0/support/include/conffile.h.orig nfs-utils-1.3.0/support/include/conffile.h +--- nfs-utils-1.3.0/support/include/conffile.h.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/include/conffile.h 2017-03-28 13:43:53.000000000 -0400 +@@ -35,6 +35,8 @@ + + #include + #include ++#include ++#include + + struct conf_list_node { + TAILQ_ENTRY(conf_list_node) link; +@@ -56,6 +58,7 @@ extern struct sockaddr *conf_get_address + extern struct conf_list *conf_get_list(char *, char *); + extern struct conf_list *conf_get_tag_list(char *, char *); + extern int conf_get_num(char *, char *, int); ++extern _Bool conf_get_bool(char *, char *, _Bool); + extern char *conf_get_str(char *, char *); + extern char *conf_get_section(char *, char *, char *); + extern void conf_init(void); +diff -up nfs-utils-1.3.0/support/include/xlog.h.orig nfs-utils-1.3.0/support/include/xlog.h +--- nfs-utils-1.3.0/support/include/xlog.h.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/include/xlog.h 2017-03-28 13:43:53.000000000 -0400 +@@ -41,6 +41,7 @@ void xlog_stderr(int on); + void xlog_syslog(int on); + void xlog_config(int fac, int on); + void xlog_sconfig(char *, int on); ++void xlog_from_conffile(char *); + int xlog_enabled(int fac); + void xlog(int fac, const char *fmt, ...); + void xlog_warn(const char *fmt, ...); +diff -up nfs-utils-1.3.0/support/nfs/conffile.c.orig nfs-utils-1.3.0/support/nfs/conffile.c +--- nfs-utils-1.3.0/support/nfs/conffile.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/conffile.c 2017-03-28 13:43:53.000000000 -0400 +@@ -52,6 +52,7 @@ + #pragma GCC visibility push(hidden) + + static void conf_load_defaults(void); ++static int conf_load(int trans, char *path); + static int conf_set(int , char *, char *, char *, + char *, int , int ); + +@@ -107,8 +108,6 @@ struct conf_binding { + char *conf_path; + LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; + +-static char *conf_addr; +- + static __inline__ u_int8_t + conf_hash(char *s) + { +@@ -213,7 +212,7 @@ static void + conf_parse_line(int trans, char *line, size_t sz) + { + char *val, *ptr; +- size_t i, valsize; ++ size_t i; + size_t j; + static char *section = 0; + static char *arg = 0; +@@ -300,18 +299,32 @@ conf_parse_line(int trans, char *line, s + } + line[strcspn (line, " \t=")] = '\0'; + val = line + i + 1 + strspn (line + i + 1, " \t"); +- valsize = 0; +- while (val[valsize++]); + +- /* Skip trailing spaces and comments */ +- for (j = 0; j < valsize; j++) { +- if (val[j] == '#' || val[j] == ';' || isspace(val[j])) { +- val[j] = '\0'; +- break; ++ if (val[0] == '"') { ++ val ++; ++ j = strcspn(val, "\""); ++ val[j] = 0; ++ } else if (val[0] == '\'') { ++ val ++; ++ j = strcspn(val, "'"); ++ val[j] = 0; ++ } else { ++ /* Skip trailing spaces and comments */ ++ for (j = 0; val[j]; j++) { ++ if ((val[j] == '#' || val[j] == ';') ++ && (j == 0 || isspace(val[j-1]))) { ++ val[j] = '\0'; ++ break; ++ } + } ++ while (j && isspace(val[j-1])) ++ val[--j] = '\0'; + } +- /* XXX Perhaps should we not ignore errors? */ +- conf_set(trans, section, arg, line, val, 0, 0); ++ if (strcasecmp(line, "include") == 0) ++ conf_load(trans, val); ++ else ++ /* XXX Perhaps should we not ignore errors? */ ++ conf_set(trans, section, arg, line, val, 0, 0); + return; + } + } +@@ -368,23 +381,18 @@ conf_init (void) + conf_reinit(); + } + +-/* Open the config file and map it into our address space, then parse it. */ +-void +-conf_reinit(void) ++static int ++conf_load(int trans, char *path) + { +- struct conf_binding *cb = 0; +- int fd, trans; +- unsigned int i; +- size_t sz; +- char *new_conf_addr = 0; + struct stat sb; ++ if ((stat (path, &sb) == 0) || (errno != ENOENT)) { ++ char *new_conf_addr; ++ size_t sz = sb.st_size; ++ int fd = open (path, O_RDONLY, 0); + +- if ((stat (conf_path, &sb) == 0) || (errno != ENOENT)) { +- sz = sb.st_size; +- fd = open (conf_path, O_RDONLY, 0); + if (fd == -1) { +- xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path); +- return; ++ xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", path); ++ return -1; + } + + new_conf_addr = malloc(sz); +@@ -396,39 +404,46 @@ conf_reinit(void) + /* XXX I assume short reads won't happen here. */ + if (read (fd, new_conf_addr, sz) != (int)sz) { + xlog_warn("conf_reinit: read (%d, %p, %lu) failed", +- fd, new_conf_addr, (unsigned long)sz); ++ fd, new_conf_addr, (unsigned long)sz); + goto fail; + } + close(fd); + +- trans = conf_begin(); + /* XXX Should we not care about errors and rollback? */ + conf_parse(trans, new_conf_addr, sz); ++ free(new_conf_addr); ++ return 0; ++ fail: ++ close(fd); ++ free(new_conf_addr); + } +- else +- trans = conf_begin(); ++ return -1; ++} ++ ++/* Open the config file and map it into our address space, then parse it. */ ++void ++conf_reinit(void) ++{ ++ struct conf_binding *cb = 0; ++ int trans; ++ unsigned int i; ++ ++ trans = conf_begin(); ++ if (conf_load(trans, conf_path) < 0) ++ return; + + /* Load default configuration values. */ + conf_load_defaults(); + + /* Free potential existing configuration. */ +- if (conf_addr) { +- for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { +- cb = LIST_FIRST (&conf_bindings[i]); +- for (; cb; cb = LIST_FIRST (&conf_bindings[i])) +- conf_remove_now(cb->section, cb->tag); +- } +- free (conf_addr); ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { ++ cb = LIST_FIRST (&conf_bindings[i]); ++ for (; cb; cb = LIST_FIRST (&conf_bindings[i])) ++ conf_remove_now(cb->section, cb->tag); + } + + conf_end(trans, 1); +- conf_addr = new_conf_addr; + return; +- +-fail: +- if (new_conf_addr) +- free(new_conf_addr); +- close (fd); + } + + /* +@@ -446,6 +461,38 @@ conf_get_num(char *section, char *tag, i + return def; + } + ++/* ++ * Return the Boolean value denoted by TAG in section SECTION, or DEF ++ * if that tags does not exist. ++ * FALSE is returned for case-insensitve comparisons with 0, f, false, n, no, off ++ * TRUE is returned for 1, t, true, y, yes, on ++ * A failure to match one of these results in DEF ++ */ ++_Bool ++conf_get_bool(char *section, char *tag, _Bool def) ++{ ++ char *value = conf_get_str(section, tag); ++ ++ if (!value) ++ return def; ++ if (strcasecmp(value, "1") == 0 || ++ strcasecmp(value, "t") == 0 || ++ strcasecmp(value, "true") == 0 || ++ strcasecmp(value, "y") == 0 || ++ strcasecmp(value, "yes") == 0 || ++ strcasecmp(value, "on") == 0) ++ return true; ++ ++ if (strcasecmp(value, "0") == 0 || ++ strcasecmp(value, "f") == 0 || ++ strcasecmp(value, "false") == 0 || ++ strcasecmp(value, "n") == 0 || ++ strcasecmp(value, "no") == 0 || ++ strcasecmp(value, "off") == 0) ++ return false; ++ return def; ++} ++ + /* Validate X according to the range denoted by TAG in section SECTION. */ + int + conf_match_num(char *section, char *tag, int x) +@@ -476,12 +523,24 @@ char * + conf_get_str(char *section, char *tag) + { + struct conf_binding *cb; +- ++retry: + cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); + for (; cb; cb = LIST_NEXT (cb, link)) { + if (strcasecmp (section, cb->section) == 0 +- && strcasecmp (tag, cb->tag) == 0) ++ && strcasecmp (tag, cb->tag) == 0) { ++ if (cb->value[0] == '$') { ++ /* expand $name from [environment] section, ++ * or from environment ++ */ ++ char *env = getenv(cb->value+1); ++ if (env && *env) ++ return env; ++ section = "environment"; ++ tag = cb->value + 1; ++ goto retry; ++ } + return cb->value; ++ } + } + return 0; + } +@@ -705,6 +764,8 @@ conf_set(int transaction, char *section, + { + struct conf_trans *node; + ++ if (!value || !*value) ++ return 0; + node = conf_trans_node(transaction, CONF_SET); + if (!node) + return 1; +diff -up nfs-utils-1.3.0/support/nfs/xlog.c.orig nfs-utils-1.3.0/support/nfs/xlog.c +--- nfs-utils-1.3.0/support/nfs/xlog.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/xlog.c 2017-03-28 13:43:53.000000000 -0400 +@@ -29,6 +29,7 @@ + #include + #include + #include "nfslib.h" ++#include "conffile.h" + + #undef VERBOSE_PRINTF + +@@ -125,6 +126,19 @@ xlog_sconfig(char *kind, int on) + xlog_config(tbl->df_fac, on); + } + ++void ++xlog_from_conffile(char *service) ++{ ++ struct conf_list *kinds; ++ struct conf_list_node *n; ++ ++ kinds = conf_get_list(service, "debug"); ++ if (!kinds || !kinds->cnt) ++ return; ++ TAILQ_FOREACH(n, &(kinds->fields), link) ++ xlog_sconfig(n->field, 1); ++} ++ + int + xlog_enabled(int fac) + { +diff -up nfs-utils-1.3.0/systemd/Makefile.am.orig nfs-utils-1.3.0/systemd/Makefile.am +--- nfs-utils-1.3.0/systemd/Makefile.am.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/Makefile.am 2017-03-28 13:43:53.000000000 -0400 +@@ -20,7 +20,9 @@ unit_files = \ + proc-fs-nfsd.mount \ + var-lib-nfs-rpc_pipefs.mount + +-EXTRA_DIST = $(unit_files) ++man5_MANS = nfs.conf.man ++man7_MANS = nfs.systemd.man ++EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS) + + unit_dir = /usr/lib/systemd/system + +diff -up nfs-utils-1.3.0/systemd/nfs.conf.man.orig nfs-utils-1.3.0/systemd/nfs.conf.man +--- nfs-utils-1.3.0/systemd/nfs.conf.man.orig 2017-03-28 13:43:53.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs.conf.man 2017-03-28 13:43:53.000000000 -0400 +@@ -0,0 +1,231 @@ ++.TH NFS.CONF 5 ++.SH NAME ++nfs.conf \- general configuration for NFS daemons and tools ++.SH SYNOPSIS ++.I /etc/nfs.conf ++.SH DESCRIPTION ++.PP ++This file contains site-specific configuration for various NFS daemons ++and other processes. Most configuration can also be passed to ++processes via command line arguments, but it can be more convenient to ++have a central file. In particular, this encourages consistent ++configuration across different processes. ++.PP ++When command line options are provided, they override values set in ++this file. When this file does not specify a particular parameter, ++and no command line option is provided, each tool provides its own ++default values. ++.PP ++The file format supports multiple sections, each of which can contain ++multiple value assignments. A section is introduced by a line ++containing the section name enclosed in square brackets, so ++.RS ++.B [global] ++.RE ++would introduce a section called ++.BR global . ++A value assignment is a single line that has the name of the value, an ++equals sign, and a setting for the value, so ++.RS ++.B threads = 4 ++.RE ++would set the value named ++.B threads ++in the current section to ++.BR 4 . ++Leading and trailing spaces and tab ++are ignored, as are spaces and tabs surrounding the equals sign. ++Single and double quotes surrounding the assigned value are also ++removed. If the resulting string is empty, the whole assignment ++is ignored. ++.PP ++Any line starting with ++.RB \*(lq # \*(rq ++or ++.RB \*(lq ; \*(rq ++is ignored, as is any blank line. ++.PP ++If the assigned value started with a ++.RB \*(lq $ \*(rq ++then the remainder is treated as a name and looked for in the section ++.B [environment] ++or in the processes environment (see ++.BR environ (7)). ++The value found is used for this value. ++.PP ++The value name ++.B include ++is special. If a section contains ++.RS ++.B include = /some/file/name ++.RE ++then the named file will be read, and any value assignments found ++there-in will be added to the current section. If the file contains ++section headers, then new sections will be created just as if the ++included file appeared in place of the ++.B include ++line. ++.PP ++Lookup of section and value names is case-insensitive. ++ ++Where a Boolean value is expected, any of ++.BR true , ++.BR t , ++.BR yes , ++.BR y , ++.BR on ", or" ++.B 1 ++can be used for "true", while ++.BR false , ++.BR f , ++.BR no , ++.BR n , ++.BR off ", or" ++.B 0 ++can be used for "false". Comparisons are case-insensitive. ++ ++.SH SECTIONS ++The following sections are known to various programs, and can contain ++the given named values. Most sections can also contain a ++.B debug ++value, which can be one or more from the list ++.BR general , ++.BR call , ++.BR auth , ++.BR parse , ++.BR all . ++When a list is given, the members should be comma-separated. ++.TP ++.B nfsdcltrack ++Recognized values: ++.BR storagedir . ++ ++The ++.B nfsdcltrack ++program is run directly by the Linux kernel and there is no ++opportunity to provide command line arguments, so the configuration ++file is the only way to configure this program. See ++.BR nfsdcltrack (8) ++for details. ++ ++.TP ++.B nfsd ++Recognized values: ++.BR threads , ++.BR host , ++.BR port , ++.BR grace-time , ++.BR lease-time , ++.BR udp , ++.BR tcp , ++.BR vers2 , ++.BR vers3 , ++.BR vers4 , ++.BR vers4.0 , ++.BR vers4.1 , ++.BR vers4.2 , ++.BR rdma . ++ ++Version and protocol values are Boolean values as described above, ++and are also used by ++.BR rpc.mountd . ++Threads and the two times are integers. ++.B port ++and ++.B rdma ++are service names or numbers. See ++.BR rpc.nfsd (8) ++for details. ++ ++.TP ++.B mountd ++Recognized values: ++.BR manage-gids , ++.BR descriptors , ++.BR port , ++.BR threads , ++.BR reverse-lookup , ++.BR state-directory-path , ++.BR ha-callout . ++ ++These, together with the protocol and version values in the ++.B [nfsd] ++section, are used to configure mountd. See ++.BR rpc.mountd (8) ++for details. ++ ++.TP ++.B statd ++Recognized values: ++.BR port , ++.BR outgoing-port , ++.BR name , ++.BR state-directory-path , ++.BR ha-callout . ++ ++See ++.BR rpc.statd (8) ++for details. ++ ++.TP ++.B lockd ++Recognized values: ++.B port ++and ++.BR udp-port . ++ ++See ++.BR rpc.statd (8) ++for details. ++ ++.TP ++.B sm-notify ++Recognized values: ++.BR retry-time , ++.BR outgoing-port ", and" ++.BR outgoing-addr . ++ ++See ++.BR sm-notify (8) ++for details. ++ ++.TP ++.B gssd ++Recognized values: ++.BR use-memcache , ++.BR use-machine-creds , ++.BR avoid-dns , ++.BR limit-to-legacy-enctypes , ++.BR context-timeout , ++.BR rpc-timeout , ++.BR pipefs-directory , ++.BR keytab-file , ++.BR cred-cache-directory , ++.BR preferred-realm . ++ ++See ++.BR rpc.gssd (8) ++for details. ++ ++.TP ++.B svcgssd ++Recognized values: ++.BR principal . ++ ++See ++.BR rpc.svcgssd (8) ++for details. ++ ++.TP ++.B exportfs ++Only ++.B debug= ++is recognized. ++ ++.SH FILES ++.I /etc/nfs.conf ++.SH SEE ALSO ++.BR nfsdcltrack (8), ++.BR rpc.nfsd (8), ++.BR rpc.mountd (8), ++.BR nfsmount.conf (5). +diff -up nfs-utils-1.3.0/systemd/nfs.systemd.man.orig nfs-utils-1.3.0/systemd/nfs.systemd.man +--- nfs-utils-1.3.0/systemd/nfs.systemd.man.orig 2017-03-28 13:45:11.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs.systemd.man 2017-03-28 13:45:11.000000000 -0400 +@@ -0,0 +1,167 @@ ++.TH NFS.SYSTEMD 7 ++.SH NAME ++nfs.systemd \- managing NFS services through systemd. ++.SH SYNOPSIS ++nfs-utils.service ++.br ++nfs-server.service ++.br ++nfs-client.target ++.br ++.I etc ++.SH DESCRIPTION ++The ++.I nfs-utils ++package provides a suite of ++.I systemd ++unit files which allow the various services to be started and ++managed. These unit files ensure that the services are started in the ++correct order, and the prerequisites are active before dependant ++services start. As there are quite few unit files, it is not ++immediately obvious how best to achieve certain results. The ++following subsections attempt to cover the issues that are most likely ++to come up. ++.SS Configuration ++The standard systemd unit files do not provide any easy way to pass ++any command line arguments to daemons so as to configure their ++behavior. In many case such configuration can be performed by making ++changes to ++.I /etc/nfs.conf ++or other configuration files. When that is not convenient, a ++distribution might provide systemd "drop-in" files which replace the ++.B ExecStart= ++setting to start the program with different arguments. For example a ++drop-in file ++.B systemd/system/nfs-mountd.service.d/local.conf ++containing ++.RS ++.nf ++[Service] ++EnvironmentFile=/etc/sysconfig/nfs ++ExecStart= ++ExecStart= /usr/sbin/rpc.mountd $RPCMOUNTDOPTS ++.fi ++.RE ++would cause the ++.B nfs-mountd.service ++unit to run the ++.I rpc.mountd ++program using, for arguments, the value given for ++.B RPCMOUNTDOPTS ++in ++.IR /etc/sysconfig/nfs . ++This allows for seamless integration with existing configuration ++tools. ++.SS Enabling unit files ++There are three unit files which are designed to be manually enabled. ++All others are automatically run as required. The three are: ++.TP ++.B nfs-client.target ++This should be enabled on any host which ever serves as an NFS client. ++There is little cost in transparently enabling it whenever NFS client ++software is installed. ++.TP ++.B nfs-server.service ++This must be enabled to provide NFS service to clients. It starts and ++configures the required daemons in the required order. ++.TP ++.B nfs-blkmap.service ++The ++.B blkmapd ++daemon is only required on NFS clients which are using pNFS (parallel ++NFS), and particularly using the ++.B blocklayout ++layout protocol. If you might use this particular extension to NFS, ++the ++.B nfs-blkmap.service ++unit should be enabled. ++.PP ++Several other units which might be considered to be optional, such as ++.I rpc-gssd.service ++are careful to only start if the required configuration file exists. ++.I rpc-gsdd.service ++will not start if the ++.I krb5.keytab ++file does not exist (typically in ++.IR /etc ). ++.SS Restarting NFS services ++Most NFS daemons can be restarted at any time. They will reload any ++state that they need, and continue servicing requests. This is rarely ++necessary though. ++.PP ++When configuration changesare make, it can be hard to know exactly ++which services need to be restarted to ensure that the configuration ++takes effect. The simplest approach, which is often the best, is to ++restart everything. To help with this, the ++.B nfs-utils.service ++unit is provided. It declares appropriate dependencies with other ++unit files so that ++.RS ++.B systemctl restart nfs-utils ++.RE ++will restart all NFS daemons that are running. This will cause all ++configuration changes to take effect ++.I except ++for changes to mount options lists in ++.I /etc/fstab ++or ++.IR /etc/nfsmount.conf . ++Mount options can only be changed by unmounting and remounting ++filesystem. This can be a disruptive operation so it should only be ++done when the value justifies the cost. The command ++.RS ++.B umount -a -t nfs; mount -a -t nfs ++.RE ++should unmount and remount all NFS filesystems. ++.SS Masking unwanted services ++Rarely there may be a desire to prohibit some services from running ++even though there are normally part of a working NFS system. This may ++be needed to reduce system load to an absolute minimum, or to reduce ++attack surface by not running daemons that are not absolutely ++required. ++.PP ++Two particular services which this can apply to are ++.I rpcbind ++and ++.IR idmapd . ++.I rpcbind ++is not part of the ++.I nfs-utils ++package, but it used by several NFS services. However it is ++.B not ++needed when only NFSv4 is in use. If a site will never use NFSv3 (or ++NFSv2) and does not want ++.I rpcbind ++to be running, the correct approach is to run ++.RS ++.B systemctl mask rpcbind ++.RE ++This will disable ++.IR rpcbind , ++and the various NFS services which depend on it (and are only needed ++for NFSv3) will refuse to start, without interfering with the ++operation of NFSv4 services. In particular, ++.I rpc.statd ++will not run when ++.I rpcbind ++is masked. ++.PP ++.I idmapd ++is only needed for NFSv4, and even then is not needed when the client ++and server agree to use user-ids rather than user-names to identify the ++owners of files. If ++.I idmapd ++is not needed and not wanted, it can be masked with ++.RS ++.B systemctl mask idmapd ++.RE ++.SH FILES ++/etc/nfs.conf ++.br ++/etc/nfsmount.conf ++.br ++/etc/idmapd.conf ++.SH SEE ALSO ++.BR systemd.unit (5), ++.BR nfs.conf (5), ++.BR nfsmount.conf (5). +diff -up nfs-utils-1.3.0/systemd/rpc-statd.service.orig nfs-utils-1.3.0/systemd/rpc-statd.service +--- nfs-utils-1.3.0/systemd/rpc-statd.service.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-statd.service 2017-03-28 13:43:53.000000000 -0400 +@@ -11,7 +11,8 @@ Wants=nfs-config.service + After=nfs-config.service + + [Service] ++Environment=RPC_STATD_NO_NOTIFY=1 + EnvironmentFile=-/run/sysconfig/nfs-utils + Type=forking + PIDFile=/var/run/rpc.statd.pid +-ExecStart=/usr/sbin/rpc.statd --no-notify $STATDARGS ++ExecStart=/usr/sbin/rpc.statd $STATDARGS +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2017-03-28 13:43:53.000000000 -0400 +@@ -37,6 +37,7 @@ + #include "nfslib.h" + #include "exportfs.h" + #include "xlog.h" ++#include "conffile.h" + + static void export_all(int verbose); + static void exportfs(char *arg, char *options, int verbose); +@@ -53,6 +54,7 @@ static void release_lockfile(void); + + static const char *lockfile = EXP_LOCKFILE; + static int _lockfd = -1; ++char *conf_path = NFS_CONFFILE; + + /* + * If we aren't careful, changes made by exportfs can be lost +@@ -108,6 +110,9 @@ main(int argc, char **argv) + xlog_stderr(1); + xlog_syslog(0); + ++ conf_init(); ++ xlog_from_conffile("exportfs"); ++ + while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) { + switch(c) { + case 'a': +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.man.orig nfs-utils-1.3.0/utils/exportfs/exportfs.man +--- nfs-utils-1.3.0/utils/exportfs/exportfs.man.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.man 2017-03-28 13:43:53.000000000 -0400 +@@ -90,6 +90,13 @@ to be added to the kernel's export table + .TP + .B \-d kind " or " \-\-debug kind + Turn on debugging. Valid kinds are: all, auth, call, general and parse. ++Debugging can also be turned on by setting ++.B debug= ++in the ++.B [exportfs] ++section of ++.IR /etc/nfs.conf . ++ + .TP + .B -a + Export or unexport all directories. +@@ -295,6 +302,7 @@ master table of exports + table of clients accessing server's exports + .SH SEE ALSO + .BR exports (5), ++.BR nfs.conf (5), + .BR rpc.mountd (8), + .BR netgroup (5) + .SH AUTHORS +diff -up nfs-utils-1.3.0/utils/gssd/gssd.c.orig nfs-utils-1.3.0/utils/gssd/gssd.c +--- nfs-utils-1.3.0/utils/gssd/gssd.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.c 2017-03-28 13:43:53.000000000 -0400 +@@ -71,6 +71,7 @@ + #include "gss_util.h" + #include "krb5_util.h" + #include "nfslib.h" ++#include "conffile.h" + + static char *pipefs_path = GSSD_PIPEFS_DIR; + static DIR *pipefs_dir; +@@ -78,6 +79,7 @@ static int pipefs_fd; + static int inotify_fd; + struct event inotify_ev; + ++char *conf_path = NFS_CONFFILE; + char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; + char **ccachesearch; + int use_memcache = 0; +@@ -831,6 +833,33 @@ main(int argc, char *argv[]) + char *progname; + char *ccachedir = NULL; + struct event sighup_ev; ++ char *s; ++ ++ conf_init(); ++ use_memcache = conf_get_bool("gssd", "use-memcache", use_memcache); ++ root_uses_machine_creds = conf_get_bool("gssd", "use-machine-creds", ++ root_uses_machine_creds); ++ avoid_dns = conf_get_bool("gssd", "avoid-dns", avoid_dns); ++#ifdef HAVE_SET_ALLOWABLE_ENCTYPES ++ limit_to_legacy_enctypes = conf_get_bool("gssd", "limit-to-legacy-enctypes", ++ limit_to_legacy_enctypes); ++#endif ++ context_timeout = conf_get_num("gssd", "context-timeout", context_timeout); ++ rpc_timeout = conf_get_num("gssd", "rpc-timeout", rpc_timeout); ++ s = conf_get_str("gssd", "pipefs-directory"); ++ if (!s) ++ s = conf_get_str("general", "pipefs-directory"); ++ if (s) ++ pipefs_path = s; ++ s = conf_get_str("gssd", "keytab-file"); ++ if (s) ++ keytabfile = s; ++ s = conf_get_str("gssd", "cred-cache-directory"); ++ if (s) ++ ccachedir = s; ++ s = conf_get_str("gssd", "preferred-realm"); ++ if (s) ++ preferred_realm = s; + + while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { + switch (opt) { +diff -up nfs-utils-1.3.0/utils/gssd/gssd.man.orig nfs-utils-1.3.0/utils/gssd/gssd.man +--- nfs-utils-1.3.0/utils/gssd/gssd.man.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.man 2017-03-28 13:43:53.000000000 -0400 +@@ -297,6 +297,60 @@ The default timeout is set to 5 seconds. + If you get messages like "WARNING: can't create tcp rpc_clnt to server + %servername% for user with uid %uid%: RPC: Remote system error - + Connection timed out", you should consider an increase of this timeout. ++.SH CONFIGURATION FILE ++Many of the options that can be set on the command line can also be ++controlled through values set in the ++.B [gssd] ++section of the ++.I /etc/nfs.conf ++configuration file. Values recognized include: ++.TP ++.B use-memcache ++A Boolean flag equivalent to ++.BR -M . ++.TP ++.B use-machine-creds ++A Boolean flag. Setting to ++.B false ++is equivalent to giving the ++.B -n ++flag. ++.TP ++.B avoid-dns ++Setting to ++.B false ++is equivalent to providing the ++.B -D ++flag. ++.TP ++.B limit-to-legacy-enctypes ++Equivalent to ++.BR -l . ++.TP ++.B context-timeout ++Equivalent to ++.BR -T . ++.TP ++.B rpc-timeout ++Equivalent to ++.BR -t . ++.TP ++.B pipefs-directory ++Equivalent to ++.BR -p . ++.TP ++.B keytab-file ++Equivalent to ++.BR -k . ++.TP ++.BR cred-cache-directory ++Equivalent to ++.BR -d . ++.TP ++.B preferred-realm ++Equivalent to ++.BR -R . ++ + .SH SEE ALSO + .BR rpc.svcgssd (8), + .BR kerberos (1), +diff -up nfs-utils-1.3.0/utils/gssd/svcgssd.c.orig nfs-utils-1.3.0/utils/gssd/svcgssd.c +--- nfs-utils-1.3.0/utils/gssd/svcgssd.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/svcgssd.c 2017-03-28 13:43:53.000000000 -0400 +@@ -61,6 +61,9 @@ + #include "svcgssd.h" + #include "gss_util.h" + #include "err_util.h" ++#include "conffile.h" ++ ++char *conf_path = NFS_CONFFILE; + + void + sig_die(int signal) +@@ -98,6 +101,17 @@ main(int argc, char *argv[]) + extern char *optarg; + char *progname; + char *principal = NULL; ++ char *s; ++ ++ conf_init(); ++ ++ s = conf_get_str("svcgssd", "principal"); ++ if (!s) ++ ; ++ else if (strcmp(s, "system")== 0) ++ get_creds = 0; ++ else ++ principal = s; + + while ((opt = getopt(argc, argv, "fivrnp:")) != -1) { + switch (opt) { +diff -up nfs-utils-1.3.0/utils/gssd/svcgssd.man.orig nfs-utils-1.3.0/utils/gssd/svcgssd.man +--- nfs-utils-1.3.0/utils/gssd/svcgssd.man.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/svcgssd.man 2017-03-28 13:43:53.000000000 -0400 +@@ -45,6 +45,23 @@ Use the system default credentials + .RI (host/ FQDN @ REALM ) + rather than the default + .RI nfs/ FQDN @ REALM . ++.SH CONFIGURATION FILE ++Some of the options that can be set on the command line can also be ++controlled through values set in the ++.B [svcgssd] ++section of the ++.I /etc/nfs.conf ++configuration file. Values recognized include: ++.TP ++.B principal ++If set to ++.B system ++this is equivalent to the ++.B -n ++option. If set to any other value, that is used like the ++.B -p ++option. ++ + .SH SEE ALSO + .BR rpc.gssd(8), + .SH AUTHORS +diff -up nfs-utils-1.3.0/utils/mountd/mountd.c.orig nfs-utils-1.3.0/utils/mountd/mountd.c +--- nfs-utils-1.3.0/utils/mountd/mountd.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mountd/mountd.c 2017-03-28 13:43:53.000000000 -0400 +@@ -22,6 +22,8 @@ + #include + #include + #include ++ ++#include "conffile.h" + #include "xmalloc.h" + #include "misc.h" + #include "mountd.h" +@@ -39,6 +41,8 @@ int new_cache = 0; + int manage_gids; + int use_ipaddr = -1; + ++char *conf_path = NFS_CONFFILE; ++ + /* PRC: a high-availability callout program can be specified with -H + * When this is done, the program will receive callouts whenever clients + * send mount or unmount requests -- the callout is not needed for 2.6 kernel */ +@@ -692,6 +696,7 @@ main(int argc, char **argv) + char *export_file = _PATH_EXPORTS; + char *state_dir = NFS_STATEDIR; + char *progname; ++ char *s; + unsigned int listeners = 0; + int foreground = 0; + int port = 0; +@@ -707,6 +712,38 @@ main(int argc, char **argv) + else + progname = argv[0]; + ++ conf_init(); ++ xlog_from_conffile("mountd"); ++ manage_gids = conf_get_bool("mountd", "manage-gids", manage_gids); ++ descriptors = conf_get_num("mountd", "descriptors", descriptors); ++ port = conf_get_num("mountd", "port", port); ++ num_threads = conf_get_num("mountd", "threads", num_threads); ++ reverse_resolve = conf_get_bool("mountd", "reverse-lookup", reverse_resolve); ++ ha_callout_prog = conf_get_str("mountd", "ha-callout"); ++ ++ s = conf_get_str("mountd", "state-directory-path"); ++ if (s) ++ state_dir = s; ++ ++ /* NOTE: following uses "nfsd" section of nfs.conf !!!! */ ++ if (conf_get_bool("nfsd", "udp", NFSCTL_UDPISSET(_rpcprotobits))) ++ NFSCTL_UDPSET(_rpcprotobits); ++ else ++ NFSCTL_UDPUNSET(_rpcprotobits); ++ if (conf_get_bool("nfsd", "tcp", NFSCTL_TCPISSET(_rpcprotobits))) ++ NFSCTL_TCPSET(_rpcprotobits); ++ else ++ NFSCTL_TCPUNSET(_rpcprotobits); ++ for (vers = 2; vers <= 4; vers++) { ++ char tag[10]; ++ sprintf(tag, "vers%d", vers); ++ if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(nfs_version, vers))) ++ NFSCTL_VERSET(nfs_version, vers); ++ else ++ NFSCTL_VERUNSET(nfs_version, vers); ++ } ++ ++ + /* Parse the command line options and arguments. */ + opterr = 0; + while ((c = getopt_long(argc, argv, "o:nFd:f:p:P:hH:N:V:vurs:t:g", longopts, NULL)) != EOF) +diff -up nfs-utils-1.3.0/utils/mountd/mountd.man.orig nfs-utils-1.3.0/utils/mountd/mountd.man +--- nfs-utils-1.3.0/utils/mountd/mountd.man.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/mountd/mountd.man 2017-03-28 13:43:53.000000000 -0400 +@@ -207,6 +207,39 @@ the server. Note that the 'primary' grou + .B newgroup + command on the client will still be effective. This function requires + a Linux Kernel with version at least 2.6.21. ++ ++.SH CONFIGURATION FILE ++Many of the options that can be set on the command line can also be ++controlled through values set in the ++.B [mountd] ++or, in some cases, the ++.B [nfsd] ++sections of the ++.I /etc/nfs.conf ++configuration file. ++Values recognized in the ++.B [mountd] ++section include ++.BR manage-gids , ++.BR descriptors , ++.BR port , ++.BR threads , ++.BR reverse-lookup ", and" ++.BR state-directory-path , ++.B ha-callout ++which each have the same effect as the option with the same name. ++ ++The values recognized in the ++.B [nfsd] ++section include ++.BR TCP , ++.BR UDP , ++.BR vers2 , ++.BR vers3 ", and" ++.B vers4 ++which each have same same meaning as given by ++.BR rpc.nfsd (8). ++ + .SH TCP_WRAPPERS SUPPORT + You can protect your + .B rpc.mountd +@@ -261,6 +294,7 @@ table of clients accessing server's expo + .BR rpc.nfsd (8), + .BR rpc.rquotad (8), + .BR nfs (5), ++.BR nfs.conf (5), + .BR tcpd (8), + .BR hosts_access (5), + .BR iptables (8), +diff -up nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.c.orig nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.c +--- nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.c 2017-03-28 13:43:53.000000000 -0400 +@@ -43,6 +43,7 @@ + #include + #endif + ++#include "conffile.h" + #include "xlog.h" + #include "sqlite.h" + +@@ -55,6 +56,8 @@ + /* defined by RFC 3530 */ + #define NFS4_OPAQUE_LIMIT 1024 + ++char *conf_path = NFS_CONFFILE; ++ + /* private data structures */ + struct cltrack_cmd { + char *name; +@@ -553,6 +556,7 @@ int + main(int argc, char **argv) + { + char arg; ++ char *val; + int rc = 0; + char *progname, *cmdarg = NULL; + struct cltrack_cmd *cmd; +@@ -562,6 +566,15 @@ main(int argc, char **argv) + xlog_syslog(1); + xlog_stderr(0); + ++ conf_init(); ++ xlog_from_conffile("nfsdcltrack"); ++ val = conf_get_str("nfsdcltrack", "storagedir"); ++ if (val) ++ storagedir = val; ++ rc = conf_get_num("nfsdcltrack", "debug", 0); ++ if (rc > 0) ++ xlog_config(D_ALL, 1); ++ + /* process command-line options */ + while ((arg = getopt_long(argc, argv, "hdfs:", longopts, + NULL)) != EOF) { +diff -up nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.man.orig nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.man +--- nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.man.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsdcltrack/nfsdcltrack.man 2017-03-28 13:43:53.000000000 -0400 +@@ -66,6 +66,20 @@ Check to see if a nfs_client_id4 is allo + .IP "\fBgracedone\fR" 4 + .IX Item "gracedone" + Remove any unreclaimed client records from the database. This command requires a epoch boot time as an argument. ++.SH "EXTERNAL CONFIGURATION" ++The directory for stable storage information can be set via the file ++.B /etc/nfs.conf ++by setting the ++.B storagedir ++value in the ++.B nfsdcltrack ++section. For example: ++.in +5 ++[nfsdcltrack] ++.br ++ storagedir = /shared/nfs/nfsdcltrack ++.in -5 ++Debuging to syslog can also be enabled by setting "debug = 1" in this file. + .SH "LEGACY TRANSITION MECHANISM" + .IX Header "LEGACY TRANSITION MECHANISM" + The Linux kernel NFSv4 server has historically tracked this information +diff -up nfs-utils-1.3.0/utils/nfsd/nfsd.c.orig nfs-utils-1.3.0/utils/nfsd/nfsd.c +--- nfs-utils-1.3.0/utils/nfsd/nfsd.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsd/nfsd.c 2017-03-28 13:43:53.000000000 -0400 +@@ -23,14 +23,18 @@ + #include + #include + ++#include "conffile.h" + #include "nfslib.h" + #include "nfssvc.h" + #include "xlog.h" ++#include "xcommon.h" + + #ifndef NFSD_NPROC + #define NFSD_NPROC 8 + #endif + ++char *conf_path = NFS_CONFFILE; ++ + static void usage(const char *); + + static struct option longopts[] = +@@ -51,50 +55,6 @@ static struct option longopts[] = + { NULL, 0, 0, 0 } + }; + +-/* given a family and ctlbits, disable any that aren't listed in netconfig */ +-#ifdef HAVE_LIBTIRPC +-static void +-nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6) +-{ +- struct netconfig *nconf; +- unsigned int *famproto; +- void *handle; +- +- xlog(D_GENERAL, "Checking netconfig for visible protocols."); +- +- handle = setnetconfig(); +- while((nconf = getnetconfig(handle))) { +- if (!(nconf->nc_flag & NC_VISIBLE)) +- continue; +- +- if (!strcmp(nconf->nc_protofmly, NC_INET)) +- famproto = proto4; +- else if (!strcmp(nconf->nc_protofmly, NC_INET6)) +- famproto = proto6; +- else +- continue; +- +- if (!strcmp(nconf->nc_proto, NC_TCP)) +- NFSCTL_TCPSET(*famproto); +- else if (!strcmp(nconf->nc_proto, NC_UDP)) +- NFSCTL_UDPSET(*famproto); +- +- xlog(D_GENERAL, "Enabling %s %s.", nconf->nc_protofmly, +- nconf->nc_proto); +- } +- endnetconfig(handle); +- return; +-} +-#else /* HAVE_LIBTIRPC */ +-static void +-nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6) +-{ +- /* Enable all IPv4 protocols if no TIRPC support */ +- *proto4 = NFSCTL_ALLBITS; +- *proto6 = 0; +-} +-#endif /* HAVE_LIBTIRPC */ +- + int + main(int argc, char **argv) + { +@@ -102,44 +62,91 @@ main(int argc, char **argv) + char *p, *progname, *port, *rdma_port = NULL; + char **haddr = NULL; + int hcounter = 0; ++ struct conf_list *hosts; + int socket_up = 0; + unsigned int minorvers = 0; + unsigned int minorversset = 0; + unsigned int versbits = NFSCTL_VERDEFAULT; + unsigned int protobits = NFSCTL_ALLBITS; +- unsigned int proto4 = 0; +- unsigned int proto6 = 0; + int grace = -1; + int lease = -1; + +- progname = strdup(basename(argv[0])); +- if (!progname) { +- fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]); +- exit(1); +- } +- +- port = strdup("nfs"); +- if (!port) { +- fprintf(stderr, "%s: unable to allocate memory.\n", progname); +- exit(1); +- } +- +- haddr = malloc(sizeof(char *)); +- if (!haddr) { +- fprintf(stderr, "%s: unable to allocate memory.\n", progname); +- exit(1); +- } ++ progname = basename(argv[0]); ++ haddr = xmalloc(sizeof(char *)); + haddr[0] = NULL; + + xlog_syslog(0); + xlog_stderr(1); + ++ conf_init(); ++ xlog_from_conffile("nfsd"); ++ count = conf_get_num("nfsd", "threads", count); ++ grace = conf_get_num("nfsd", "grace-time", grace); ++ lease = conf_get_num("nfsd", "lease-time", lease); ++ port = conf_get_str("nfsd", "port"); ++ if (!port) ++ port = "nfs"; ++ rdma_port = conf_get_str("nfsd", "rdma"); ++ if (conf_get_bool("nfsd", "udp", NFSCTL_UDPISSET(protobits))) ++ NFSCTL_UDPSET(protobits); ++ else ++ NFSCTL_UDPUNSET(protobits); ++ if (conf_get_bool("nfsd", "tcp", NFSCTL_TCPISSET(protobits))) ++ NFSCTL_TCPSET(protobits); ++ else ++ NFSCTL_TCPUNSET(protobits); ++ for (i = 2; i <= 4; i++) { ++ char tag[10]; ++ sprintf(tag, "vers%d", i); ++ if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(versbits, i))) ++ NFSCTL_VERSET(versbits, i); ++ else ++ NFSCTL_VERUNSET(versbits, i); ++ } ++ /* We assume the kernel will default all minor versions to 'on', ++ * and allow the config file to disable some. ++ */ ++ for (i = NFS4_MINMINOR; i <= NFS4_MAXMINOR; i++) { ++ char tag[20]; ++ sprintf(tag, "vers4.%d", i); ++ /* The default for minor version support is to let the ++ * kernel decide. We could ask the kernel what that choice ++ * will be, but that is needlessly complex. ++ * Instead, perform a config-file lookup using each of the ++ * two possible default. If the result is different from the ++ * default, then impose that value, else don't make a change ++ * (i.e. don't set the bit in minorversset). ++ */ ++ if (!conf_get_bool("nfsd", tag, 1)) { ++ NFSCTL_VERSET(minorversset, i); ++ NFSCTL_VERUNSET(minorvers, i); ++ } ++ if (conf_get_bool("nfsd", tag, 0)) { ++ NFSCTL_VERSET(minorversset, i); ++ NFSCTL_VERSET(minorvers, i); ++ } ++ } ++ ++ hosts = conf_get_list("nfsd", "host"); ++ if (hosts && hosts->cnt) { ++ struct conf_list_node *n; ++ haddr = realloc(haddr, sizeof(char*) * hosts->cnt); ++ TAILQ_FOREACH(n, &(hosts->fields), link) { ++ haddr[hcounter] = n->field; ++ hcounter++; ++ } ++ } ++ + while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTUrG:L:", longopts, NULL)) != EOF) { + switch(c) { + case 'd': + xlog_config(D_ALL, 1); + break; + case 'H': ++ if (hosts) { ++ hosts = NULL; ++ hcounter = 0; ++ } + if (hcounter) { + haddr = realloc(haddr, sizeof(char*) * hcounter+1); + if(!haddr) { +@@ -148,30 +155,13 @@ main(int argc, char **argv) + exit(1); + } + } +- haddr[hcounter] = strdup(optarg); +- if (!haddr[hcounter]) { +- fprintf(stderr, "%s: unable to allocate " +- "memory.\n", progname); +- exit(1); +- } ++ haddr[hcounter] = optarg; + hcounter++; + break; + case 'P': /* XXX for nfs-server compatibility */ + case 'p': + /* only the last -p option has any effect */ +- portnum = atoi(optarg); +- if (portnum <= 0 || portnum > 65535) { +- fprintf(stderr, "%s: bad port number: %s\n", +- progname, optarg); +- usage(progname); +- } +- free(port); +- port = strdup(optarg); +- if (!port) { +- fprintf(stderr, "%s: unable to allocate " +- "memory.\n", progname); +- exit(1); +- } ++ port = optarg; + break; + case 'r': + rdma_port = "nfsrdma"; +@@ -188,7 +178,7 @@ main(int argc, char **argv) + case 4: + if (*p == '.') { + int i = atoi(p+1); +- if (i > NFS4_MAXMINOR) { ++ if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) { + fprintf(stderr, "%s: unsupported minor version\n", optarg); + exit(1); + } +@@ -210,7 +200,7 @@ main(int argc, char **argv) + case 4: + if (*p == '.') { + int i = atoi(p+1); +- if (i > NFS4_MAXMINOR) { ++ if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) { + fprintf(stderr, "%s: unsupported minor version\n", optarg); + exit(1); + } +@@ -277,18 +267,6 @@ main(int argc, char **argv) + + xlog_open(progname); + +- nfsd_enable_protos(&proto4, &proto6); +- +- if (!NFSCTL_TCPISSET(protobits)) { +- NFSCTL_TCPUNSET(proto4); +- NFSCTL_TCPUNSET(proto6); +- } +- +- if (!NFSCTL_UDPISSET(protobits)) { +- NFSCTL_UDPUNSET(proto4); +- NFSCTL_UDPUNSET(proto6); +- } +- + /* make sure that at least one version is enabled */ + found_one = 0; + for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) { +@@ -301,8 +279,7 @@ main(int argc, char **argv) + } + + if (NFSCTL_VERISSET(versbits, 4) && +- !NFSCTL_TCPISSET(proto4) && +- !NFSCTL_TCPISSET(proto6)) { ++ !NFSCTL_TCPISSET(protobits)) { + xlog(L_ERROR, "version 4 requires the TCP protocol"); + exit(1); + } +@@ -336,15 +313,10 @@ main(int argc, char **argv) + + i = 0; + do { +- error = nfssvc_set_sockets(AF_INET, proto4, haddr[i], port); +- if (!error) +- socket_up = 1; +-#ifdef IPV6_SUPPORTED +- error = nfssvc_set_sockets(AF_INET6, proto6, haddr[i], port); ++ error = nfssvc_set_sockets(protobits, haddr[i], port); + if (!error) + socket_up = 1; +-#endif /* IPV6_SUPPORTED */ +- } while (++i < hcounter); ++ } while (++i < hcounter); + + if (rdma_port) { + error = nfssvc_set_rdmaport(rdma_port); +@@ -381,11 +353,7 @@ set_threads: + if ((error = nfssvc_threads(portnum, count)) < 0) + xlog(L_ERROR, "error starting threads: errno %d (%m)", errno); + out: +- free(port); +- for(i=0; i < hcounter; i++) +- free(haddr[i]); + free(haddr); +- free(progname); + return (error != 0); + } + +diff -up nfs-utils-1.3.0/utils/nfsd/nfsd.man.orig nfs-utils-1.3.0/utils/nfsd/nfsd.man +--- nfs-utils-1.3.0/utils/nfsd/nfsd.man.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsd/nfsd.man 2017-03-28 13:43:53.000000000 -0400 +@@ -57,7 +57,7 @@ This option can be used to request that + .B rpc.nfsd + does not offer certain versions of NFS. The current version of + .B rpc.nfsd +-can support NFS versions 2,3,4 and the newer version 4.1. ++can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2. + .TP + .B \-s " or " \-\-syslog + By default, +@@ -82,7 +82,7 @@ This option can be used to request that + .B rpc.nfsd + offer certain versions of NFS. The current version of + .B rpc.nfsd +-can support NFS versions 2,3,4 and the newer version 4.1. ++can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2. + .TP + .B \-L " or " \-\-lease-time seconds + Set the lease-time used for NFSv4. This corresponds to how often +@@ -95,11 +95,11 @@ New file open requests (NFSv4) and new f + allowed until after this time has passed to allow clients to recover state. + .TP + .I nproc +-specify the number of NFS server threads. By default, just one +-thread is started. However, for optimum performance several threads ++specify the number of NFS server threads. By default, eight ++threads are started. However, for optimum performance several threads + should be used. The actual figure depends on the number of and the work + load created by the NFS clients, but a useful starting point is +-8 threads. Effects of modifying that number can be checked using ++eight threads. Effects of modifying that number can be checked using + the + .BR nfsstat (8) + program. +@@ -114,6 +114,58 @@ In particular + .B rpc.nfsd 0 + will stop all threads and thus close any open connections. + ++.SH CONFIGURATION FILE ++Many of the options that can be set on the command line can also be ++controlled through values set in the ++.B [nfsd] ++section of the ++.I /etc/nfs.conf ++configuration file. Values recognized include: ++.TP ++.B threads ++The number of threads to start. ++.TP ++.B host ++A host name, or comma separated list of host names, that ++.I rpc.nfsd ++will listen on. Use of the ++.B --host ++option replaces all host names listed here. ++.TP ++.B grace-time ++The grace time, for both NFSv4 and NLM, in seconds. ++.TP ++.B lease-time ++The lease time for NFSv4, in seconds. ++.TP ++.B port ++Set the port for TCP/UDP to bind to. ++.TP ++.B rdma ++Set RDMA port. Use "rdma=nfsrdma" to enable standard port. ++.TP ++.B UDP ++Enable (with "on" or "yes" etc) or disable ("off", "no") UDP support. ++.TP ++.B TCP ++Enable or disable TCP support. ++.TP ++.B vers2 ++.TP ++.B vers3 ++.TP ++.B vers4 ++Enable or disable a major NFS version. 3 and 4 are normally enabled ++by default. ++.TP ++.B vers4.1 ++.TP ++.B vers4.2 ++Setting these to "off" or similar will disable the selected minor ++versions. Setting to "on" will enable them. The default values ++are determined by the kernel, and usually minor versions default to ++being enabled once the implementation is sufficiently complete. ++ + .SH NOTES + If the program is built with TI-RPC support, it will enable any protocol and + address family combinations that are marked visible in the +@@ -124,6 +176,7 @@ database. + .BR rpc.mountd (8), + .BR exports (5), + .BR exportfs (8), ++.BR nfs.conf (5), + .BR rpc.rquotad (8), + .BR nfsstat (8), + .BR netconfig(5). +diff -up nfs-utils-1.3.0/utils/nfsd/nfssvc.c.orig nfs-utils-1.3.0/utils/nfsd/nfssvc.c +--- nfs-utils-1.3.0/utils/nfsd/nfssvc.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsd/nfssvc.c 2017-03-28 13:43:53.000000000 -0400 +@@ -23,6 +23,7 @@ + + #include "nfslib.h" + #include "xlog.h" ++#include "nfssvc.h" + + #ifndef NFSD_FS_DIR + #define NFSD_FS_DIR "/proc/fs/nfsd" +@@ -123,22 +124,6 @@ nfssvc_setfds(const struct addrinfo *hin + if (fd < 0) + return 0; + +- switch(hints->ai_family) { +- case AF_INET: +- family = "inet"; +- break; +-#ifdef IPV6_SUPPORTED +- case AF_INET6: +- family = "inet6"; +- break; +-#endif /* IPV6_SUPPORTED */ +- default: +- xlog(L_ERROR, "Unknown address family specified: %d\n", +- hints->ai_family); +- rc = EAFNOSUPPORT; +- goto error; +- } +- + rc = getaddrinfo(node, port, hints, &addrhead); + if (rc == EAI_NONAME && !strcmp(port, "nfs")) { + snprintf(buf, sizeof(buf), "%d", NFS_PORT); +@@ -146,10 +131,10 @@ nfssvc_setfds(const struct addrinfo *hin + } + + if (rc != 0) { +- xlog(L_ERROR, "unable to resolve %s:%s to %s address: " +- "%s", node ? node : "ANYADDR", port, family, +- rc == EAI_SYSTEM ? strerror(errno) : +- gai_strerror(rc)); ++ xlog(L_ERROR, "unable to resolve %s:%s: %s", ++ node ? node : "ANYADDR", port, ++ rc == EAI_SYSTEM ? strerror(errno) : ++ gai_strerror(rc)); + goto error; + } + +@@ -168,6 +153,20 @@ nfssvc_setfds(const struct addrinfo *hin + continue; + } + ++ switch(addr->ai_addr->sa_family) { ++ case AF_INET: ++ family = "AF_INET"; ++ break; ++#ifdef IPV6_SUPPORTED ++ case AF_INET6: ++ family = "AF_INET6"; ++ break; ++#endif /* IPV6_SUPPORTED */ ++ default: ++ addr = addr->ai_next; ++ continue; ++ } ++ + xlog(D_GENERAL, "Creating %s %s socket.", family, proto); + + /* open socket and prepare to hand it off to kernel */ +@@ -251,12 +250,16 @@ error: + } + + int +-nfssvc_set_sockets(const int family, const unsigned int protobits, ++nfssvc_set_sockets(const unsigned int protobits, + const char *host, const char *port) + { + struct addrinfo hints = { .ai_flags = AI_PASSIVE }; + +- hints.ai_family = family; ++#ifdef IPV6_SUPPORTED ++ hints.ai_family = AF_UNSPEC; ++#else /* IPV6_SUPPORTED */ ++ hints.ai_family = AF_INET; ++#endif /* IPV6_SUPPORTED */ + + if (!NFSCTL_ANYPROTO(protobits)) + return EPROTOTYPE; +diff -up nfs-utils-1.3.0/utils/nfsd/nfssvc.h.orig nfs-utils-1.3.0/utils/nfsd/nfssvc.h +--- nfs-utils-1.3.0/utils/nfsd/nfssvc.h.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsd/nfssvc.h 2017-03-28 13:43:53.000000000 -0400 +@@ -22,7 +22,7 @@ + + void nfssvc_mount_nfsdfs(char *progname); + int nfssvc_inuse(void); +-int nfssvc_set_sockets(const int family, const unsigned int protobits, ++int nfssvc_set_sockets(const unsigned int protobits, + const char *host, const char *port); + void nfssvc_set_time(const char *type, const int seconds); + int nfssvc_set_rdmaport(const char *port); +diff -up nfs-utils-1.3.0/utils/statd/sm-notify.c.orig nfs-utils-1.3.0/utils/statd/sm-notify.c +--- nfs-utils-1.3.0/utils/statd/sm-notify.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/statd/sm-notify.c 2017-03-28 13:43:53.000000000 -0400 +@@ -29,6 +29,7 @@ + #include + #include + ++#include "conffile.h" + #include "sockaddr.h" + #include "xlog.h" + #include "nsm.h" +@@ -64,6 +65,7 @@ static _Bool opt_update_state = true; + static unsigned int opt_max_retry = 15 * 60; + static char * opt_srcaddr = NULL; + static char * opt_srcport = NULL; ++char * conf_path = NFS_CONFFILE; + + static void notify(const int sock); + static int notify_host(int, struct nsm_host *); +@@ -455,6 +457,7 @@ main(int argc, char **argv) + { + int c, sock, force = 0; + char * progname; ++ char * s; + + progname = strrchr(argv[0], '/'); + if (progname != NULL) +@@ -462,6 +465,15 @@ main(int argc, char **argv) + else + progname = argv[0]; + ++ conf_init(); ++ xlog_from_conffile("sm-notify"); ++ opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60; ++ opt_srcport = conf_get_str("sm-notify", "outgoing-port"); ++ opt_srcaddr = conf_get_str("sm-notify", "outgoing-addr"); ++ s = conf_get_str("statd", "state-directory-path"); ++ if (s && !nsm_setup_pathnames(argv[0], s)) ++ exit(1); ++ + while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) { + switch (c) { + case 'f': +diff -up nfs-utils-1.3.0/utils/statd/sm-notify.man.orig nfs-utils-1.3.0/utils/statd/sm-notify.man +--- nfs-utils-1.3.0/utils/statd/sm-notify.man.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/statd/sm-notify.man 2017-03-28 13:43:53.000000000 -0400 +@@ -219,6 +219,33 @@ argument when sending SM_NOTIFY requests + .IP + This option can be useful in multi-homed configurations where + the remote requires notification from a specific network address. ++.SH CONFIGURATION FILE ++Many of the options that can be set on the command line can also be ++controlled through values set in the ++.B [sm-notify] ++or, in one case, the ++.B [statd] ++section of the ++.I /etc/nfs.conf ++configuration file. ++ ++Values recognized in the ++.B [sm-notify] ++section include: ++.BR retry-time , ++.BR outgoing-port ", and" ++.BR outgoing-addr . ++These have the same effect as the command line options ++.BR m , ++.BR p ", and" ++.B v ++respectively. ++ ++The value recognized in the ++.B [statd] ++section is ++.BR state-directory-path . ++ + .SH SECURITY + The + .B sm-notify +diff -up nfs-utils-1.3.0/utils/statd/statd.c.orig nfs-utils-1.3.0/utils/statd/statd.c +--- nfs-utils-1.3.0/utils/statd/statd.c.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/statd/statd.c 2017-03-28 13:43:53.000000000 -0400 +@@ -26,6 +26,7 @@ + #include + #include + ++#include "conffile.h" + #include "statd.h" + #include "nfslib.h" + #include "nfsrpc.h" +@@ -36,6 +37,7 @@ + #include + + int run_mode = 0; /* foreground logging mode */ ++char *conf_path = NFS_CONFFILE; + + /* LH - I had these local to main, but it seemed silly to have + * two copies of each - one in main(), one static in log.c... +@@ -242,15 +244,21 @@ static void set_nlm_port(char *type, int + int main (int argc, char **argv) + { + extern char *optarg; ++ char *s; + int pid; + int arg; + int port = 0, out_port = 0; + int nlm_udp = 0, nlm_tcp = 0; + struct rlimit rlim; ++ char *env; + + /* Default: daemon mode, no other options */ + run_mode = 0; + ++ env = getenv("RPC_STATD_NO_NOTIFY"); ++ if (env && atoi(env) > 0) ++ run_mode |= MODE_NO_NOTIFY; ++ + /* Log to stderr if there's an error during startup */ + xlog_stderr(1); + xlog_syslog(0); +@@ -265,6 +273,24 @@ int main (int argc, char **argv) + /* Set hostname */ + MY_NAME = NULL; + ++ conf_init(); ++ xlog_from_conffile("statd"); ++ out_port = conf_get_num("statd", "outgoing-port", out_port); ++ port = conf_get_num("statd", "port", port); ++ MY_NAME = conf_get_str("statd", "name"); ++ if (MY_NAME) ++ run_mode |= STATIC_HOSTNAME; ++ s = conf_get_str("statd", "state-directory-path"); ++ if (s && !nsm_setup_pathnames(argv[0], s)) ++ exit(1); ++ s = conf_get_str("statd", "ha-callout"); ++ if (s) ++ ha_callout_prog = s; ++ ++ nlm_tcp = conf_get_num("lockd", "port", nlm_tcp); ++ /* udp defaults to the same as tcp ! */ ++ nlm_udp = conf_get_num("lockd", "udp-port", nlm_tcp); ++ + /* Process command line switches */ + while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:LT:U:", longopts, NULL)) != EOF) { + switch (arg) { +diff -up nfs-utils-1.3.0/utils/statd/statd.man.orig nfs-utils-1.3.0/utils/statd/statd.man +--- nfs-utils-1.3.0/utils/statd/statd.man.orig 2017-03-28 13:43:36.000000000 -0400 ++++ nfs-utils-1.3.0/utils/statd/statd.man 2017-03-28 13:43:53.000000000 -0400 +@@ -8,7 +8,7 @@ + .\" Rewritten by Chuck Lever , 2009. + .\" Copyright 2009 Oracle. All rights reserved. + .\" +-.TH RPC.STATD 8 "1 November 2009 ++.TH RPC.STATD 8 "1 November 2009" + .SH NAME + rpc.statd \- NSM service daemon + .SH SYNOPSIS +@@ -247,7 +247,7 @@ should listen on for + .B NLM + requests. + .TP +-.BI "\-P, " "" \-\-state\-directory\-path " pathname ++.BI "\-P, " "" \-\-state\-directory\-path " pathname" + Specifies the pathname of the parent directory + where NSM state information resides. + If this option is not specified, +@@ -267,6 +267,37 @@ Causes + to display version information on + .I stderr + and then exit. ++.SH CONFIGURATION FILE ++Many of the options that can be set on the command line can also be ++controlled through values set in the ++.B [statd] ++or, in some cases, the ++.B [lockd] ++sections of the ++.I /etc/nfs.conf ++configuration file. ++Values recognized in the ++.B [statd] ++section include ++.BR port , ++.BR outgoing-port , ++.BR name , ++.BR state-directory-path ", and" ++.B ha-callout ++which each have the same effect as the option with the same name. ++ ++The values recognized in the ++.B [lockd] ++section include ++.B port ++and ++.B udp-port ++which have the same effect as the ++.B --nlm-port ++and ++.B --nlm-udp-port ++options, respectively. ++ + .SH SECURITY + The + .B rpc.statd +@@ -387,6 +418,11 @@ it attempts to start listeners on networ + As long as at least one network transport listener starts successfully, + .B rpc.statd + will operate. ++.SH ENVIRONMENT ++.TP ++.B RPC_STATD_NO_NOTIFY= ++If set to a positive integer, has the same effect as ++.IR \-\-no\-notify . + .SH FILES + .TP 2.5i + .I /var/lib/nfs/sm diff --git a/SOURCES/nfs-utils-1.3.0-nfs_connect_nb-eintr.patch b/SOURCES/nfs-utils-1.3.0-nfs_connect_nb-eintr.patch new file mode 100644 index 0000000..1f1f49a --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfs_connect_nb-eintr.patch @@ -0,0 +1,33 @@ +diff -up nfs-utils-1.3.0/support/nfs/rpc_socket.c.orig nfs-utils-1.3.0/support/nfs/rpc_socket.c +--- nfs-utils-1.3.0/support/nfs/rpc_socket.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/rpc_socket.c 2016-04-28 11:37:53.694236000 -0400 +@@ -215,7 +215,7 @@ static int nfs_connect_nb(const int fd, + * use it later. + */ + ret = connect(fd, sap, salen); +- if (ret < 0 && errno != EINPROGRESS) { ++ if (ret < 0 && errno != EINPROGRESS && errno != EINTR) { + ret = -1; + goto done; + } +@@ -227,10 +227,16 @@ static int nfs_connect_nb(const int fd, + FD_ZERO(&rset); + FD_SET(fd, &rset); + +- ret = select(fd + 1, NULL, &rset, NULL, timeout); +- if (ret <= 0) { +- if (ret == 0) +- errno = ETIMEDOUT; ++ while ((ret = select(fd + 1, NULL, &rset, NULL, timeout)) < 0) { ++ if (errno != EINTR) { ++ ret = -1; ++ goto done; ++ } else { ++ continue; ++ } ++ } ++ if (ret == 0) { ++ errno = ETIMEDOUT; + ret = -1; + goto done; + } diff --git a/SOURCES/nfs-utils-1.3.0-nfsclient-after.patch b/SOURCES/nfs-utils-1.3.0-nfsclient-after.patch new file mode 100644 index 0000000..2fddcd8 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsclient-after.patch @@ -0,0 +1,12 @@ +diff -up rhel7/systemd/nfs-client.target.orig rhel7/systemd/nfs-client.target +--- rhel7/systemd/nfs-client.target.orig 2014-03-25 11:12:07.000000000 -0400 ++++ rhel7/systemd/nfs-client.target 2014-09-29 11:16:15.470237681 -0400 +@@ -7,7 +7,7 @@ Wants=remote-fs-pre.target + # start that on demand if needed. + Wants=rpc-gssd.service rpc-svcgssd.service + Wants=nfs-blkmap.service rpc-statd-notify.service +-Before=rpc-gssd.service rpc-svcgssd.service nfs-blkmap.service ++After=rpc-gssd.service rpc-svcgssd.service nfs-blkmap.service + + [Install] + WantedBy=multi-user.target diff --git a/SOURCES/nfs-utils-1.3.0-nfsd-man-correction.patch b/SOURCES/nfs-utils-1.3.0-nfsd-man-correction.patch new file mode 100644 index 0000000..8455de8 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsd-man-correction.patch @@ -0,0 +1,41 @@ +commit c7896bec9699473959fc51baf3686149a470a30b +Author: Chris Siebenmann +Date: Tue Mar 14 10:41:39 2017 -0400 + + Manual page bug: two inaccuracies in nfsd(7) + + Here is a patch that deletes the mention of auth.domain and changes the + wording around 'flush' files. I'm not attached to the revised wording; + it's just the best I could manage in something that felt that it was + within the same style and space as the current wording. + + Acked-by: NeilBrown + Signed-off-by: Chris Siebenmann + Signed-off-by: Steve Dickson + +diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man +index 0c516fa..9efa29f 100644 +--- a/utils/exportfs/nfsd.man ++++ b/utils/exportfs/nfsd.man +@@ -105,11 +105,6 @@ clients have for different filesystems. + The caches are: + + .TP +-.B auth.domain +-This cache maps the name of a client (or domain) to an internal data +-structure. The only access that is possible is to flush the cache. +- +-.TP + .B auth.unix.ip + This cache contains a mapping from IP address to the name of the + authentication domain that the ipaddress should be treated as part of. +@@ -133,7 +128,8 @@ are: + .B flush + When a number of seconds since epoch (1 Jan 1970) is written to this + file, all entries in the cache that were last updated before that file +-become invalidated and will be flushed out. Writing 1 will flush ++become invalidated and will be flushed out. Writing a time in the ++future (in seconds since epoch) will flush + everything. This is the only file that will always be present. + + .TP diff --git a/SOURCES/nfs-utils-1.3.0-nfsd-rdma.patch b/SOURCES/nfs-utils-1.3.0-nfsd-rdma.patch new file mode 100644 index 0000000..f9b5827 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsd-rdma.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/utils/nfsd/nfssvc.c.orig nfs-utils-1.3.0/utils/nfsd/nfssvc.c +--- nfs-utils-1.3.0/utils/nfsd/nfssvc.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsd/nfssvc.c 2016-05-17 10:42:05.000000000 -0400 +@@ -278,7 +278,7 @@ nfssvc_set_rdmaport(const char *port) + int fd; + + if (sv) +- nport = sv->s_port; ++ nport = ntohs(sv->s_port); + else { + char *ep; + nport = strtol(port, &ep, 10); diff --git a/SOURCES/nfs-utils-1.3.0-nfsd-warnings.patch b/SOURCES/nfs-utils-1.3.0-nfsd-warnings.patch new file mode 100644 index 0000000..71879bc --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsd-warnings.patch @@ -0,0 +1,26 @@ +commit a2e431fdd114f2c2466573471dafef9024392f2d +Author: Steve Dickson +Date: Wed Apr 30 12:26:06 2014 -0400 + + nfsd: Remove some warnings nfsd.c + + nfsd.c:347:15: warning: comparison between signed and unsigned integer + expressions [-Wsign-compare] + nfsd.c:385:13: warning: comparison between signed and unsigned integer + expressions [-Wsign-compare] + + Signed-off-by: Steve Dickson + +diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c +index 73d6a92..03e3c81 100644 +--- a/utils/nfsd/nfsd.c ++++ b/utils/nfsd/nfsd.c +@@ -101,7 +101,7 @@ main(int argc, char **argv) + int count = NFSD_NPROC, c, i, error = 0, portnum = 0, fd, found_one; + char *p, *progname, *port, *rdma_port = NULL; + char **haddr = NULL; +- unsigned int hcounter = 0; ++ int hcounter = 0; + int socket_up = 0; + unsigned int minorvers = 0; + unsigned int minorversset = 0; diff --git a/SOURCES/nfs-utils-1.3.0-nfsdcltrack-errors.patch b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-errors.patch new file mode 100644 index 0000000..54af57f --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-errors.patch @@ -0,0 +1,37 @@ +commit 06bbb4ee6f5186e8e83d50767ad5b3b41968e5a6 +Author: Jeff Layton +Date: Wed Apr 26 12:13:50 2017 -0400 + + nfsdcltrack: silence some expected errors + + On a new install, we're unable to select from the parameters table, as + it doesn't exist yet. The code is set up to log that fact at L_ERROR + now, but it's an expected situation. Change it to log that at D_GENERAL + instead. + + Reported-and-Tested-by: ChunYu Wang + Signed-off-by: Jeff Layton + Signed-off-by: Steve Dickson + +diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c +index 54cd748..1552eba 100644 +--- a/utils/nfsdcltrack/sqlite.c ++++ b/utils/nfsdcltrack/sqlite.c +@@ -101,7 +101,7 @@ sqlite_query_schema_version(void) + "SELECT value FROM parameters WHERE key == \"version\";", + -1, &stmt, NULL); + if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to prepare select statement: %s", ++ xlog(D_GENERAL, "Unable to prepare select statement: %s", + sqlite3_errmsg(dbh)); + ret = 0; + goto out; +@@ -110,7 +110,7 @@ sqlite_query_schema_version(void) + /* query schema version */ + ret = sqlite3_step(stmt); + if (ret != SQLITE_ROW) { +- xlog(L_ERROR, "Select statement execution failed: %s", ++ xlog(D_GENERAL, "Select statement execution failed: %s", + sqlite3_errmsg(dbh)); + ret = 0; + goto out; diff --git a/SOURCES/nfs-utils-1.3.0-nfsdcltrack-usage.patch b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-usage.patch new file mode 100644 index 0000000..0d08563 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-usage.patch @@ -0,0 +1,21 @@ +commit daf0838e30f896d02ca51becc99578713c1be4cb +Author: Steve Dickson +Date: Wed Dec 7 13:35:49 2016 -0500 + + Fixed typo in usage string + + Signed-off-by: Steve Dickson + +diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c +index e6e514b..fd64153 100644 +--- a/utils/nfsdcltrack/nfsdcltrack.c ++++ b/utils/nfsdcltrack/nfsdcltrack.c +@@ -100,7 +100,7 @@ static unsigned char blob[NFS4_OPAQUE_LIMIT]; + static void + usage(char *progname) + { +- printf("%s [ -hfd ] [ -s dir ] < cmd > < arg >\n", progname); ++ printf("Usage: %s [ -hfd ] [ -s dir ] < cmd > < arg >\n", progname); + printf("Where < cmd > is one of the following and takes the following < arg >:\n"); + printf(" init\n"); + printf(" create \n"); diff --git a/SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema-update.patch b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema-update.patch new file mode 100644 index 0000000..c6139f4 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema-update.patch @@ -0,0 +1,154 @@ +diff -up nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c.orig nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c +--- nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c.orig 2016-02-10 10:46:23.100398000 -0500 ++++ nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c 2016-02-10 10:46:59.540317000 -0500 +@@ -29,7 +29,9 @@ + * + * clients: an "id" column containing a BLOB with the long-form clientid as + * sent by the client, a "time" column containing a timestamp (in +- * epoch seconds) of when the record was last updated. ++ * epoch seconds) of when the record was last updated, and a ++ * "has_session" column containing a boolean value indicating ++ * whether the client has sessions (v4.1+) or not (v4.0). + */ + + #ifdef HAVE_CONFIG_H +@@ -50,7 +52,7 @@ + + #include "xlog.h" + +-#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 1 ++#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 2 + + /* in milliseconds */ + #define CLTRACK_SQLITE_BUSY_TIMEOUT 10000 +@@ -120,6 +122,81 @@ out: + return ret; + } + ++static int ++sqlite_maindb_update_v1_to_v2(void) ++{ ++ int ret, ret2; ++ char *err; ++ ++ /* begin transaction */ ++ ret = sqlite3_exec(dbh, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL, ++ &err); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to begin transaction: %s", err); ++ goto rollback; ++ } ++ ++ /* ++ * Check schema version again. This time, under an exclusive ++ * transaction to guard against racing DB setup attempts ++ */ ++ ret = sqlite_query_schema_version(); ++ switch (ret) { ++ case 1: ++ /* Still at v1 -- do conversion */ ++ break; ++ case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION: ++ /* Someone else raced in and set it up */ ++ ret = 0; ++ goto rollback; ++ default: ++ /* Something went wrong -- fail! */ ++ ret = -EINVAL; ++ goto rollback; ++ } ++ ++ /* create v2 clients table */ ++ ret = sqlite3_exec(dbh, "ALTER TABLE clients ADD COLUMN " ++ "has_session INTEGER;", ++ NULL, NULL, &err); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to update clients table: %s", err); ++ goto rollback; ++ } ++ ++ ret = snprintf(buf, sizeof(buf), "UPDATE parameters SET value = %d " ++ "WHERE key = \"version\";", ++ CLTRACK_SQLITE_LATEST_SCHEMA_VERSION); ++ if (ret < 0) { ++ xlog(L_ERROR, "sprintf failed!"); ++ goto rollback; ++ } else if ((size_t)ret >= sizeof(buf)) { ++ xlog(L_ERROR, "sprintf output too long! (%d chars)", ret); ++ ret = -EINVAL; ++ goto rollback; ++ } ++ ++ ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to update schema version: %s", err); ++ goto rollback; ++ } ++ ++ ret = sqlite3_exec(dbh, "COMMIT TRANSACTION;", NULL, NULL, &err); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to commit transaction: %s", err); ++ goto rollback; ++ } ++out: ++ sqlite3_free(err); ++ return ret; ++rollback: ++ ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); ++ if (ret2 != SQLITE_OK) ++ xlog(L_ERROR, "Unable to rollback transaction: %s", err); ++ goto out; ++} ++ + /* + * Start an exclusive transaction and recheck the DB schema version. If it's + * still zero (indicating a new database) then set it up. If that all works, +@@ -127,9 +204,9 @@ out: + * transaction. On any error, rollback the transaction. + */ + int +-sqlite_maindb_init_v1(void) ++sqlite_maindb_init_v2(void) + { +- int ret; ++ int ret, ret2; + char *err = NULL; + + /* Start a transaction */ +@@ -169,7 +246,7 @@ sqlite_maindb_init_v1(void) + + /* create the "clients" table */ + ret = sqlite3_exec(dbh, "CREATE TABLE clients (id BLOB PRIMARY KEY, " +- "time INTEGER);", ++ "time INTEGER, has_session INTEGER);", + NULL, NULL, &err); + if (ret != SQLITE_OK) { + xlog(L_ERROR, "Unable to create clients table: %s", err); +@@ -207,7 +284,9 @@ out: + + rollback: + /* Attempt to rollback the transaction */ +- sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); ++ ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); ++ if (ret2 != SQLITE_OK) ++ xlog(L_ERROR, "Unable to rollback transaction: %s", err); + goto out; + } + +@@ -255,9 +334,15 @@ sqlite_prepare_dbh(const char *topdir) + /* DB is already set up. Do nothing */ + ret = 0; + break; ++ case 1: ++ /* Old DB -- update to new schema */ ++ ret = sqlite_maindb_update_v1_to_v2(); ++ if (ret) ++ goto out_close; ++ break; + case 0: + /* Query failed -- try to set up new DB */ +- ret = sqlite_maindb_init_v1(); ++ ret = sqlite_maindb_init_v2(); + if (ret) + goto out_close; + break; diff --git a/SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema.patch b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema.patch new file mode 100644 index 0000000..2331f2b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema.patch @@ -0,0 +1,850 @@ +diff --git a/Makefile.am b/Makefile.am +index c9e9f87..6f3f3d6 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -9,34 +9,6 @@ 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/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/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/utils/gssd/Makefile.am b/utils/gssd/Makefile.am +index af59791..a4e9c56 100644 +--- a/utils/gssd/Makefile.am ++++ b/utils/gssd/Makefile.am +@@ -8,7 +8,6 @@ sbin_PREFIXED = gssd svcgssd + sbin_PROGRAMS = $(sbin_PREFIXED) + + EXTRA_DIST = \ +- gss_destroy_creds \ + $(man8_MANS) + + COMMON_SRCS = \ +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/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/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/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am +index a860ffb..d603f92 100644 +--- a/utils/nfsdcltrack/Makefile.am ++++ b/utils/nfsdcltrack/Makefile.am +@@ -6,6 +6,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/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c +index 4334340..fcdda7f 100644 +--- a/utils/nfsdcltrack/nfsdcltrack.c ++++ b/utils/nfsdcltrack/nfsdcltrack.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #ifdef HAVE_SYS_CAPABILITY_H + #include + #include +@@ -49,6 +50,8 @@ + #define CLD_DEFAULT_STORAGEDIR NFS_STATEDIR "/nfsdcltrack" + #endif + ++#define NFSD_END_GRACE_FILE "/proc/fs/nfsd/v4_end_grace" ++ + /* defined by RFC 3530 */ + #define NFS4_OPAQUE_LIMIT 1024 + +@@ -210,6 +213,64 @@ cltrack_set_caps(void) + return ret; + } + ++/* Inform the kernel that it's OK to lift nfsd's grace period */ ++static void ++cltrack_lift_grace_period(void) ++{ ++ int fd; ++ ++ fd = open(NFSD_END_GRACE_FILE, O_WRONLY); ++ if (fd < 0) { ++ /* Don't warn if file isn't present */ ++ if (errno != ENOENT) ++ xlog(L_WARNING, "Unable to open %s: %m", ++ NFSD_END_GRACE_FILE); ++ return; ++ } ++ ++ if (write(fd, "Y", 1) < 0) ++ xlog(L_WARNING, "Unable to write to %s: %m", ++ NFSD_END_GRACE_FILE); ++ ++ close(fd); ++ return; ++} ++ ++/* ++ * Fetch the contents of the NFSDCLTRACK_GRACE_START env var. If it's not set ++ * or there's an error converting it to time_t, then return LONG_MAX. ++ */ ++static time_t ++cltrack_get_grace_start(void) ++{ ++ time_t grace_start; ++ char *end; ++ char *grace_start_str = getenv("NFSDCLTRACK_GRACE_START"); ++ ++ if (!grace_start_str) ++ return LONG_MAX; ++ ++ errno = 0; ++ grace_start = strtol(grace_start_str, &end, 0); ++ /* Problem converting or value is too large? */ ++ if (errno) ++ return LONG_MAX; ++ ++ return grace_start; ++} ++ ++static bool ++cltrack_reclaims_complete(void) ++{ ++ time_t grace_start = cltrack_get_grace_start(); ++ ++ /* Don't query DB if we didn't get a valid boot time */ ++ if (grace_start == LONG_MAX) ++ return false; ++ ++ return !sqlite_query_reclaiming(grace_start); ++} ++ + static int + cltrack_init(const char __attribute__((unused)) *unused) + { +@@ -241,7 +302,7 @@ cltrack_init(const char __attribute__((unused)) *unused) + } + + /* set up storage db */ +- ret = sqlite_maindb_init(storagedir); ++ ret = sqlite_prepare_dbh(storagedir); + if (ret) { + xlog(L_ERROR, "Failed to init database: %d", ret); + /* +@@ -250,15 +311,36 @@ cltrack_init(const char __attribute__((unused)) *unused) + * stop upcalling until the problem is resolved. + */ + ret = -EACCES; ++ } else { ++ if (cltrack_reclaims_complete()) ++ cltrack_lift_grace_period(); + } ++ + return ret; + } + ++/* ++ * Fetch the contents of the NFSDCLTRACK_CLIENT_HAS_SESSION env var. If ++ * it's set and the first character is 'Y' then return true. Otherwise ++ * return false. ++ */ ++static bool ++cltrack_client_has_session(void) ++{ ++ char *has_session = getenv("NFSDCLTRACK_CLIENT_HAS_SESSION"); ++ ++ if (has_session && *has_session == 'Y') ++ return true; ++ ++ return false; ++} ++ + static int + cltrack_create(const char *id) + { + int ret; + ssize_t len; ++ bool has_session; + + xlog(D_GENERAL, "%s: create client record.", __func__); + +@@ -270,7 +352,12 @@ cltrack_create(const char *id) + if (len < 0) + return (int)len; + +- ret = sqlite_insert_client(blob, len); ++ has_session = cltrack_client_has_session(); ++ ++ ret = sqlite_insert_client(blob, len, has_session, false); ++ ++ if (!ret && has_session && cltrack_reclaims_complete()) ++ cltrack_lift_grace_period(); + + return ret ? -EREMOTEIO : ret; + } +@@ -297,7 +384,8 @@ cltrack_remove(const char *id) + } + + static int +-cltrack_check_legacy(const unsigned char *blob, const ssize_t len) ++cltrack_check_legacy(const unsigned char *blob, const ssize_t len, ++ bool has_session) + { + int ret; + struct stat st; +@@ -323,7 +411,7 @@ cltrack_check_legacy(const unsigned char *blob, const ssize_t len) + } + + /* Dir exists, try to insert record into db */ +- ret = sqlite_insert_client(blob, len); ++ ret = sqlite_insert_client(blob, len, has_session, has_session); + if (ret) { + xlog(D_GENERAL, "Failed to insert client: %d", ret); + return -EREMOTEIO; +@@ -343,6 +431,7 @@ cltrack_check(const char *id) + { + int ret; + ssize_t len; ++ bool has_session; + + xlog(D_GENERAL, "%s: check client record", __func__); + +@@ -354,9 +443,11 @@ cltrack_check(const char *id) + if (len < 0) + return (int)len; + +- ret = sqlite_check_client(blob, len); ++ has_session = cltrack_client_has_session(); ++ ++ ret = sqlite_check_client(blob, len, has_session); + if (ret) +- ret = cltrack_check_legacy(blob, len); ++ ret = cltrack_check_legacy(blob, len, has_session); + + return ret ? -EPERM : ret; + } +diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c +index bac6789..eb1711a 100644 +--- a/utils/nfsdcltrack/sqlite.c ++++ b/utils/nfsdcltrack/sqlite.c +@@ -21,17 +21,15 @@ + * Explanation: + * + * This file contains the code to manage the sqlite backend database for the +- * clstated upcall daemon. ++ * nfsdcltrack usermodehelper upcall program. + * + * The main database is called main.sqlite and contains the following tables: + * + * parameters: simple key/value pairs for storing database info + * +- * clients: one column containing a BLOB with the as sent by the client +- * and a timestamp (in epoch seconds) of when the record was +- * established +- * +- * FIXME: should we also record the fsid being accessed? ++ * clients: an "id" column containing a BLOB with the long-form clientid as ++ * sent by the client, a "time" column containing a timestamp (in ++ * epoch seconds) of when the record was last updated. + */ + + #ifdef HAVE_CONFIG_H +@@ -52,10 +50,10 @@ + + #include "xlog.h" + +-#define CLD_SQLITE_SCHEMA_VERSION 1 ++#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 1 + + /* in milliseconds */ +-#define CLD_SQLITE_BUSY_TIMEOUT 10000 ++#define CLTRACK_SQLITE_BUSY_TIMEOUT 10000 + + /* private data structures */ + +@@ -90,135 +88,192 @@ mkdir_if_not_exist(const char *dirname) + return ret; + } + +-/* Open the database and set up the database handle for it */ +-int +-sqlite_prepare_dbh(const char *topdir) ++static int ++sqlite_query_schema_version(void) + { + int ret; ++ sqlite3_stmt *stmt = NULL; + +- /* Do nothing if the database handle is already set up */ +- if (dbh) +- return 0; +- +- ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", topdir); +- if (ret < 0) +- return ret; +- +- buf[PATH_MAX - 1] = '\0'; +- +- ret = sqlite3_open(buf, &dbh); ++ /* prepare select query */ ++ ret = sqlite3_prepare_v2(dbh, ++ "SELECT value FROM parameters WHERE key == \"version\";", ++ -1, &stmt, NULL); + if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to open main database: %d", ret); +- dbh = NULL; +- return ret; ++ xlog(L_ERROR, "Unable to prepare select statement: %s", ++ sqlite3_errmsg(dbh)); ++ ret = 0; ++ goto out; + } + +- ret = sqlite3_busy_timeout(dbh, CLD_SQLITE_BUSY_TIMEOUT); +- if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to set sqlite busy timeout: %d", ret); +- sqlite3_close(dbh); +- dbh = NULL; ++ /* query schema version */ ++ ret = sqlite3_step(stmt); ++ if (ret != SQLITE_ROW) { ++ xlog(L_ERROR, "Select statement execution failed: %s", ++ sqlite3_errmsg(dbh)); ++ ret = 0; ++ goto out; + } + ++ ret = sqlite3_column_int(stmt, 0); ++out: ++ sqlite3_finalize(stmt); + return ret; + } + + /* +- * Open the "main" database, and attempt to initialize it by creating the +- * parameters table and inserting the schema version into it. Ignore any errors +- * from that, and then attempt to select the version out of it again. If the +- * version appears wrong, then assume that the DB is corrupt or has been +- * upgraded, and return an error. If all of that works, then attempt to create +- * the "clients" table. ++ * Start an exclusive transaction and recheck the DB schema version. If it's ++ * still zero (indicating a new database) then set it up. If that all works, ++ * then insert schema version into the parameters table and commit the ++ * transaction. On any error, rollback the transaction. + */ + int +-sqlite_maindb_init(const char *topdir) ++sqlite_maindb_init_v1(void) + { + int ret; + char *err = NULL; +- sqlite3_stmt *stmt = NULL; + +- ret = mkdir_if_not_exist(topdir); +- if (ret) ++ /* Start a transaction */ ++ ret = sqlite3_exec(dbh, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL, ++ &err); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to begin transaction: %s", err); + return ret; ++ } + +- ret = sqlite_prepare_dbh(topdir); +- if (ret) +- return ret; ++ /* ++ * Check schema version again. This time, under an exclusive ++ * transaction to guard against racing DB setup attempts ++ */ ++ ret = sqlite_query_schema_version(); ++ switch (ret) { ++ case 0: ++ /* Query failed again -- set up DB */ ++ break; ++ case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION: ++ /* Someone else raced in and set it up */ ++ ret = 0; ++ goto rollback; ++ default: ++ /* Something went wrong -- fail! */ ++ ret = -EINVAL; ++ goto rollback; ++ } + +- /* Try to create table */ +- ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS parameters " ++ ret = sqlite3_exec(dbh, "CREATE TABLE parameters " + "(key TEXT PRIMARY KEY, value TEXT);", + NULL, NULL, &err); + if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to create parameter table: %d", ret); +- goto out_err; ++ xlog(L_ERROR, "Unable to create parameter table: %s", err); ++ goto rollback; + } + +- /* insert version into table -- ignore error if it fails */ +- ret = snprintf(buf, sizeof(buf), +- "INSERT OR IGNORE INTO parameters values (\"version\", " +- "\"%d\");", CLD_SQLITE_SCHEMA_VERSION); ++ /* create the "clients" table */ ++ ret = sqlite3_exec(dbh, "CREATE TABLE clients (id BLOB PRIMARY KEY, " ++ "time INTEGER);", ++ NULL, NULL, &err); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to create clients table: %s", err); ++ goto rollback; ++ } ++ ++ ++ /* insert version into parameters table */ ++ ret = snprintf(buf, sizeof(buf), "INSERT OR FAIL INTO parameters " ++ "values (\"version\", \"%d\");", ++ CLTRACK_SQLITE_LATEST_SCHEMA_VERSION); + if (ret < 0) { +- goto out_err; ++ xlog(L_ERROR, "sprintf failed!"); ++ goto rollback; + } else if ((size_t)ret >= sizeof(buf)) { ++ xlog(L_ERROR, "sprintf output too long! (%d chars)", ret); + ret = -EINVAL; +- goto out_err; ++ goto rollback; + } + + ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err); + if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to insert into parameter table: %d", +- ret); +- goto out_err; ++ xlog(L_ERROR, "Unable to insert into parameter table: %s", err); ++ goto rollback; + } + +- ret = sqlite3_prepare_v2(dbh, +- "SELECT value FROM parameters WHERE key == \"version\";", +- -1, &stmt, NULL); ++ ret = sqlite3_exec(dbh, "COMMIT TRANSACTION;", NULL, NULL, &err); + if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to prepare select statement: %d", ret); +- goto out_err; ++ xlog(L_ERROR, "Unable to commit transaction: %s", err); ++ goto rollback; + } ++out: ++ sqlite3_free(err); ++ return ret; + +- /* check schema version */ +- ret = sqlite3_step(stmt); +- if (ret != SQLITE_ROW) { +- xlog(L_ERROR, "Select statement execution failed: %s", ++rollback: ++ /* Attempt to rollback the transaction */ ++ sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); ++ goto out; ++} ++ ++/* Open the database and set up the database handle for it */ ++int ++sqlite_prepare_dbh(const char *topdir) ++{ ++ int ret; ++ ++ /* Do nothing if the database handle is already set up */ ++ if (dbh) ++ return 0; ++ ++ ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", topdir); ++ if (ret < 0) ++ return ret; ++ ++ buf[PATH_MAX - 1] = '\0'; ++ ++ /* open a new DB handle */ ++ ret = sqlite3_open(buf, &dbh); ++ if (ret != SQLITE_OK) { ++ /* try to create the dir */ ++ ret = mkdir_if_not_exist(topdir); ++ if (ret) ++ goto out_close; ++ ++ /* retry open */ ++ ret = sqlite3_open(buf, &dbh); ++ if (ret != SQLITE_OK) ++ goto out_close; ++ } ++ ++ /* set busy timeout */ ++ ret = sqlite3_busy_timeout(dbh, CLTRACK_SQLITE_BUSY_TIMEOUT); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "Unable to set sqlite busy timeout: %s", + sqlite3_errmsg(dbh)); +- goto out_err; ++ goto out_close; + } + +- /* process SELECT result */ +- ret = sqlite3_column_int(stmt, 0); +- if (ret != CLD_SQLITE_SCHEMA_VERSION) { ++ ret = sqlite_query_schema_version(); ++ switch (ret) { ++ case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION: ++ /* DB is already set up. Do nothing */ ++ ret = 0; ++ break; ++ case 0: ++ /* Query failed -- try to set up new DB */ ++ ret = sqlite_maindb_init_v1(); ++ if (ret) ++ goto out_close; ++ break; ++ default: ++ /* Unknown DB version -- downgrade? Fail */ + xlog(L_ERROR, "Unsupported database schema version! " + "Expected %d, got %d.", +- CLD_SQLITE_SCHEMA_VERSION, ret); ++ CLTRACK_SQLITE_LATEST_SCHEMA_VERSION, ret); + ret = -EINVAL; +- goto out_err; +- } +- +- /* now create the "clients" table */ +- ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS clients " +- "(id BLOB PRIMARY KEY, time INTEGER);", +- NULL, NULL, &err); +- if (ret != SQLITE_OK) { +- xlog(L_ERROR, "Unable to create clients table: %s", err); +- goto out_err; ++ goto out_close; + } + +- sqlite3_free(err); +- sqlite3_finalize(stmt); +- return 0; +- +-out_err: +- if (err) { +- xlog(L_ERROR, "sqlite error: %s", err); +- sqlite3_free(err); +- } +- sqlite3_finalize(stmt); ++ return ret; ++out_close: + sqlite3_close(dbh); ++ dbh = NULL; + return ret; + } + +@@ -228,14 +283,20 @@ out_err: + * Returns a non-zero sqlite error code, or SQLITE_OK (aka 0) + */ + int +-sqlite_insert_client(const unsigned char *clname, const size_t namelen) ++sqlite_insert_client(const unsigned char *clname, const size_t namelen, ++ const bool has_session, const bool zerotime) + { + int ret; + sqlite3_stmt *stmt = NULL; + +- ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients VALUES " +- "(?, strftime('%s', 'now'));", -1, +- &stmt, NULL); ++ if (zerotime) ++ ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients " ++ "VALUES (?, 0, ?);", -1, &stmt, NULL); ++ else ++ ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients " ++ "VALUES (?, strftime('%s', 'now'), ?);", -1, ++ &stmt, NULL); ++ + if (ret != SQLITE_OK) { + xlog(L_ERROR, "%s: insert statement prepare failed: %s", + __func__, sqlite3_errmsg(dbh)); +@@ -250,6 +311,13 @@ sqlite_insert_client(const unsigned char *clname, const size_t namelen) + goto out_err; + } + ++ ret = sqlite3_bind_int(stmt, 2, (int)has_session); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "%s: bind int failed: %s", __func__, ++ sqlite3_errmsg(dbh)); ++ goto out_err; ++ } ++ + ret = sqlite3_step(stmt); + if (ret == SQLITE_DONE) + ret = SQLITE_OK; +@@ -305,7 +373,8 @@ out_err: + * return an error. + */ + int +-sqlite_check_client(const unsigned char *clname, const size_t namelen) ++sqlite_check_client(const unsigned char *clname, const size_t namelen, ++ const bool has_session) + { + int ret; + sqlite3_stmt *stmt = NULL; +@@ -340,6 +409,12 @@ sqlite_check_client(const unsigned char *clname, const size_t namelen) + goto out_err; + } + ++ /* Only update timestamp for v4.0 clients */ ++ if (has_session) { ++ ret = SQLITE_OK; ++ goto out_err; ++ } ++ + sqlite3_finalize(stmt); + stmt = NULL; + ret = sqlite3_prepare_v2(dbh, "UPDATE OR FAIL clients SET " +@@ -398,3 +473,43 @@ sqlite_remove_unreclaimed(time_t grace_start) + sqlite3_free(err); + return ret; + } ++ ++/* ++ * Are there any clients that are possibly still reclaiming? Return a positive ++ * integer (usually number of clients) if so. If not, then return 0. On any ++ * error, return non-zero. ++ */ ++int ++sqlite_query_reclaiming(const time_t grace_start) ++{ ++ int ret; ++ sqlite3_stmt *stmt = NULL; ++ ++ ret = sqlite3_prepare_v2(dbh, "SELECT count(*) FROM clients WHERE " ++ "time < ? OR has_session != 1", -1, &stmt, NULL); ++ if (ret != SQLITE_OK) { ++ xlog(L_ERROR, "%s: unable to prepare select statement: %s", ++ __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_errmsg(dbh)); ++ return ret; ++ } ++ ++ ret = sqlite3_step(stmt); ++ if (ret != SQLITE_ROW) { ++ xlog(L_ERROR, "%s: unexpected return code from select: %s", ++ __func__, sqlite3_errmsg(dbh)); ++ return ret; ++ } ++ ++ ret = sqlite3_column_int(stmt, 0); ++ sqlite3_finalize(stmt); ++ xlog(D_GENERAL, "%s: there are %d clients that have not completed " ++ "reclaim", __func__, ret); ++ return ret; ++} +diff --git a/utils/nfsdcltrack/sqlite.h b/utils/nfsdcltrack/sqlite.h +index ebf04c3..06e7c04 100644 +--- a/utils/nfsdcltrack/sqlite.h ++++ b/utils/nfsdcltrack/sqlite.h +@@ -21,10 +21,12 @@ + #define _SQLITE_H_ + + int sqlite_prepare_dbh(const char *topdir); +-int sqlite_maindb_init(const char *topdir); +-int sqlite_insert_client(const unsigned char *clname, const size_t namelen); ++int sqlite_insert_client(const unsigned char *clname, const size_t namelen, ++ const bool has_session, const bool zerotime); + int sqlite_remove_client(const unsigned char *clname, const size_t namelen); +-int sqlite_check_client(const unsigned char *clname, const size_t namelen); ++int sqlite_check_client(const unsigned char *clname, const size_t namelen, ++ const bool has_session); + int sqlite_remove_unreclaimed(const time_t grace_start); ++int sqlite_query_reclaiming(const time_t grace_start); + + #endif /* _SQLITE_H */ +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/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/SOURCES/nfs-utils-1.3.0-nfsidmap-h-opt.patch b/SOURCES/nfs-utils-1.3.0-nfsidmap-h-opt.patch new file mode 100644 index 0000000..646f4c0 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsidmap-h-opt.patch @@ -0,0 +1,55 @@ +diff -up nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c.orig nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c +--- nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c.orig 2016-06-08 09:59:09.920690710 -0400 ++++ nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c 2016-06-08 11:22:01.104971559 -0400 +@@ -16,7 +16,7 @@ + #include "conffile.h" + + int verbose = 0; +-char *usage = "Usage: %s [-v] [-c || [-u|-g|-r key] || -d || -l || [-t timeout] key desc]"; ++char *usage = "Usage: %s [-vh] [-c || [-u|-g|-r key] || -d || -l || [-t timeout] key desc]"; + + #define MAX_ID_LEN 11 + #define IDMAP_NAMESZ 128 +@@ -355,7 +355,7 @@ int main(int argc, char **argv) + + xlog_open(progname); + +- while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) { ++ while ((opt = getopt(argc, argv, "hdu:g:r:ct:vl")) != -1) { + switch (opt) { + case 'd': + display++; +@@ -384,9 +384,10 @@ int main(int argc, char **argv) + case 't': + timeout = atoi(optarg); + break; ++ case 'h': + default: + xlog_warn(usage, progname); +- break; ++ exit(opt == 'h' ? 0 : 1); + } + } + +diff -up nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.man.orig nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.man +--- nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.man.orig 2016-06-08 09:59:09.899690366 -0400 ++++ nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.man 2016-06-08 11:22:01.104971559 -0400 +@@ -15,6 +15,8 @@ nfsidmap \- The NFS idmapper upcall prog + .B "nfsidmap -d" + .br + .B "nfsidmap -l" ++.br ++.B "nfsidmap -h" + .SH DESCRIPTION + The NFSv4 protocol represents the local system's UID and GID values + on the wire as strings of the form +@@ -71,6 +73,9 @@ Display the system's effective NFSv4 dom + .B -g user + Revoke the gid key of the given user. + .TP ++.B -h ++Display usage message. ++.TP + .B -l + Display on + .I stdout diff --git a/SOURCES/nfs-utils-1.3.0-nfsidmap-timeout.patch b/SOURCES/nfs-utils-1.3.0-nfsidmap-timeout.patch new file mode 100644 index 0000000..ddae35b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsidmap-timeout.patch @@ -0,0 +1,22 @@ +diff -up nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c.save nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c +--- nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c.save 2015-11-24 09:29:53.332040370 -0500 ++++ nfs-utils-1.3.0/utils/nfsidmap/nfsidmap.c 2015-11-24 09:30:06.579249849 -0500 +@@ -24,7 +24,7 @@ char *usage="Usage: %s [-v] [-c || [-u|- + + #define PROCKEYS "/proc/keys" + #ifndef DEFAULT_KEYRING +-#define DEFAULT_KEYRING "id_resolver" ++#define DEFAULT_KEYRING ".id_resolver" + #endif + + #ifndef PATH_IDMAPDCONF +@@ -315,6 +315,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/SOURCES/nfs-utils-1.3.0-nfsidmap-update.patch b/SOURCES/nfs-utils-1.3.0-nfsidmap-update.patch new file mode 100644 index 0000000..e6d1867 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsidmap-update.patch @@ -0,0 +1,574 @@ +diff --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4 +index a392c0e..16b225d 100644 +--- a/aclocal/keyutils.m4 ++++ b/aclocal/keyutils.m4 +@@ -8,4 +8,8 @@ AC_DEFUN([AC_KEYUTILS], [ + + AC_CHECK_HEADERS([keyutils.h]) + ++ AC_CHECK_LIB([keyutils], [find_key_by_type_and_desc], ++ [AC_DEFINE([HAVE_FIND_KEY_BY_TYPE_AND_DESC], [1], ++ [Define to 1 if you have the `find_key_by_type_and_desc' function.])],) ++ + ])dnl +diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c +index 10f69f9..9c49d42 100644 +--- a/utils/nfsidmap/nfsidmap.c ++++ b/utils/nfsidmap/nfsidmap.c +@@ -1,3 +1,4 @@ ++#include "config.h" + + #include + #include +@@ -15,7 +16,7 @@ + #include "conffile.h" + + int verbose = 0; +-char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; ++char *usage = "Usage: %s [-v] [-c || [-u|-g|-r key] || -d || -l || [-t timeout] key desc]"; + + #define MAX_ID_LEN 11 + #define IDMAP_NAMESZ 128 +@@ -31,15 +32,163 @@ char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; + #define PATH_IDMAPDCONF "/etc/idmapd.conf" + #endif + +-static int keyring_clear(char *keyring); +- + #define UIDKEYS 0x1 + #define GIDKEYS 0x2 + ++#ifndef HAVE_FIND_KEY_BY_TYPE_AND_DESC ++static key_serial_t find_key_by_type_and_desc(const char *type, ++ const char *desc, key_serial_t destringid) ++{ ++ char buf[BUFSIZ]; ++ key_serial_t key; ++ FILE *fp; ++ ++ if ((fp = fopen(PROCKEYS, "r")) == NULL) { ++ xlog_err("fopen(%s) failed: %m", PROCKEYS); ++ return -1; ++ } ++ ++ key = -1; ++ while(fgets(buf, BUFSIZ, fp) != NULL) { ++ unsigned int id; ++ ++ if (strstr(buf, type) == NULL) ++ continue; ++ if (strstr(buf, desc) == NULL) ++ continue; ++ if (sscanf(buf, "%x %*s", &id) != 1) { ++ xlog_err("Unparsable keyring entry in %s", PROCKEYS); ++ continue; ++ } ++ ++ key = (key_serial_t)id; ++ break; ++ } ++ ++ fclose(fp); ++ return key; ++} ++#endif ++ ++/* ++ * Clear all the keys on the given keyring ++ */ ++static int keyring_clear(const char *keyring) ++{ ++ key_serial_t key; ++ ++ key = find_key_by_type_and_desc("keyring", keyring, 0); ++ if (key == -1) { ++ if (verbose) ++ xlog_warn("'%s' keyring was not found.", keyring); ++ return EXIT_SUCCESS; ++ } ++ ++ if (keyctl_clear(key) < 0) { ++ xlog_err("keyctl_clear(0x%x) failed: %m", ++ (unsigned int)key); ++ return EXIT_FAILURE; ++ } ++ ++ if (verbose) ++ xlog_warn("'%s' cleared", keyring); ++ return EXIT_SUCCESS; ++} ++ ++static int display_default_domain(void) ++{ ++ char domain[NFS4_MAX_DOMAIN_LEN]; ++ int rc; ++ ++ rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); ++ if (rc) { ++ xlog_errno(rc, "nfs4_get_default_domain failed: %m"); ++ return EXIT_FAILURE; ++ } ++ ++ printf("%s\n", domain); ++ return EXIT_SUCCESS; ++} ++ ++static void list_key(key_serial_t key) ++{ ++ char *buffer, *c; ++ int rc; ++ ++ rc = keyctl_describe_alloc(key, &buffer); ++ if (rc < 0) { ++ switch (errno) { ++ case EKEYEXPIRED: ++ printf("Expired key not displayed\n"); ++ break; ++ default: ++ xlog_err("Failed to describe key: %m"); ++ } ++ return; ++ } ++ ++ c = strrchr(buffer, ';'); ++ if (!c) { ++ xlog_err("Unparsable key not displayed\n"); ++ goto out_free; ++ } ++ printf(" %s\n", ++c); ++ ++out_free: ++ free(buffer); ++} ++ ++static void list_keys(const char *ring_name, key_serial_t ring_id) ++{ ++ key_serial_t *key; ++ void *keylist; ++ int count; ++ ++ count = keyctl_read_alloc(ring_id, &keylist); ++ if (count < 0) { ++ xlog_err("Failed to read keyring %s: %m", ring_name); ++ return; ++ } ++ count /= (int)sizeof(*key); ++ ++ switch (count) { ++ case 0: ++ printf("No %s keys found.\n", ring_name); ++ break; ++ case 1: ++ printf("1 %s key found:\n", ring_name); ++ break; ++ default: ++ printf("%u %s keys found:\n", count, ring_name); ++ } ++ ++ for (key = keylist; count--; key++) ++ list_key(*key); ++ ++ free(keylist); ++} ++ ++/* ++ * List all keys on a keyring ++ */ ++static int list_keyring(const char *keyring) ++{ ++ key_serial_t key; ++ ++ key = find_key_by_type_and_desc("keyring", keyring, 0); ++ if (key == -1) { ++ xlog_err("'%s' keyring was not found.", keyring); ++ return EXIT_FAILURE; ++ } ++ ++ list_keys(keyring, key); ++ return EXIT_SUCCESS; ++} ++ + /* + * Find either a user or group id based on the name@domain string + */ +-int id_lookup(char *name_at_domain, key_serial_t key, int type) ++static int id_lookup(char *name_at_domain, key_serial_t key, int type) + { + char id[MAX_ID_LEN]; + uid_t uid = 0; +@@ -53,30 +202,33 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type) + rc = nfs4_group_owner_to_gid(name_at_domain, &gid); + sprintf(id, "%u", gid); + } +- if (rc < 0) ++ if (rc < 0) { + xlog_errno(rc, "id_lookup: %s: failed: %m", + (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); ++ return EXIT_FAILURE; ++ } + +- if (rc == 0) { +- rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); +- if (rc < 0) { +- switch(rc) { +- case -EDQUOT: +- case -ENFILE: +- case -ENOMEM: +- /* +- * The keyring is full. Clear the keyring and try again +- */ +- rc = keyring_clear(DEFAULT_KEYRING); +- if (rc == 0) +- rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); +- break; +- default: ++ rc = EXIT_SUCCESS; ++ if (keyctl_instantiate(key, id, strlen(id) + 1, 0)) { ++ switch (errno) { ++ case EDQUOT: ++ case ENFILE: ++ case ENOMEM: ++ /* ++ * The keyring is full. Clear the keyring and try again ++ */ ++ rc = keyring_clear(DEFAULT_KEYRING); ++ if (rc) + break; ++ if (keyctl_instantiate(key, id, strlen(id) + 1, 0)) { ++ rc = EXIT_FAILURE; ++ xlog_err("id_lookup: keyctl_instantiate failed: %m"); + } ++ break; ++ default: ++ rc = EXIT_FAILURE; ++ break; + } +- if (rc < 0) +- xlog_err("id_lookup: keyctl_instantiate failed: %m"); + } + + return rc; +@@ -85,7 +237,7 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type) + /* + * Find the name@domain string from either a user or group id + */ +-int name_lookup(char *id, key_serial_t key, int type) ++static int name_lookup(char *id, key_serial_t key, int type) + { + char name[IDMAP_NAMESZ]; + char domain[NFS4_MAX_DOMAIN_LEN]; +@@ -94,11 +246,10 @@ int name_lookup(char *id, key_serial_t key, int type) + int rc; + + rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); +- if (rc != 0) { ++ if (rc) { + xlog_errno(rc, + "name_lookup: nfs4_get_default_domain failed: %m"); +- rc = -1; +- goto out; ++ return EXIT_FAILURE; + } + + if (type == USER) { +@@ -108,61 +259,21 @@ int name_lookup(char *id, key_serial_t key, int type) + gid = atoi(id); + rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); + } +- if (rc < 0) ++ if (rc) { + xlog_errno(rc, "name_lookup: %s: failed: %m", + (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); +- +- if (rc == 0) { +- rc = keyctl_instantiate(key, &name, strlen(name), 0); +- if (rc < 0) +- xlog_err("name_lookup: keyctl_instantiate failed: %m"); ++ return EXIT_FAILURE; + } +-out: +- return rc; +-} +-/* +- * Clear all the keys on the given keyring +- */ +-static int keyring_clear(char *keyring) +-{ +- FILE *fp; +- char buf[BUFSIZ]; +- key_serial_t key; + +- if (keyring == NULL) +- keyring = DEFAULT_KEYRING; +- +- if ((fp = fopen(PROCKEYS, "r")) == NULL) { +- xlog_err("fopen(%s) failed: %m", PROCKEYS); +- return 1; ++ rc = EXIT_SUCCESS; ++ if (keyctl_instantiate(key, &name, strlen(name), 0)) { ++ rc = EXIT_FAILURE; ++ xlog_err("name_lookup: keyctl_instantiate failed: %m"); + } + +- while(fgets(buf, BUFSIZ, fp) != NULL) { +- if (strstr(buf, "keyring") == NULL) +- continue; +- if (strstr(buf, keyring) == NULL) +- continue; +- if (verbose) { +- *(strchr(buf, '\n')) = '\0'; +- xlog_warn("clearing '%s'", buf); +- } +- /* +- * The key is the first arugment in the string +- */ +- *(strchr(buf, ' ')) = '\0'; +- sscanf(buf, "%x", &key); +- if (keyctl_clear(key) < 0) { +- xlog_err("keyctl_clear(0x%x) failed: %m", key); +- fclose(fp); +- return 1; +- } +- fclose(fp); +- return 0; +- } +- xlog_err("'%s' keyring was not found.", keyring); +- fclose(fp); +- return 1; ++ return rc; + } ++ + /* + * Revoke a key + */ +@@ -177,7 +288,7 @@ static int key_invalidate(char *keystr, int keymask) + + if ((fp = fopen(PROCKEYS, "r")) == NULL) { + xlog_err("fopen(%s) failed: %m", PROCKEYS); +- return 1; ++ return EXIT_FAILURE; + } + + while(fgets(buf, BUFSIZ, fp) != NULL) { +@@ -211,18 +322,18 @@ static int key_invalidate(char *keystr, int keymask) + if (keyctl_invalidate(key) < 0) { + xlog_err("keyctl_invalidate(0x%x) failed: %m", key); + fclose(fp); +- return 1; ++ return EXIT_FAILURE; + } + + keymask &= ~mask; + if (keymask == 0) { + fclose(fp); +- return 0; ++ return EXIT_SUCCESS; + } + } + xlog_err("'%s' key was not found.", keystr); + fclose(fp); +- return 1; ++ return EXIT_FAILURE; + } + + int main(int argc, char **argv) +@@ -234,7 +345,7 @@ int main(int argc, char **argv) + int timeout = 600; + key_serial_t key; + char *progname, *keystr = NULL; +- int clearing = 0, keymask = 0; ++ int clearing = 0, keymask = 0, display = 0, list = 0; + + /* Set the basename */ + if ((progname = strrchr(argv[0], '/')) != NULL) +@@ -244,8 +355,14 @@ int main(int argc, char **argv) + + xlog_open(progname); + +- while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { ++ while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) { + switch (opt) { ++ case 'd': ++ display++; ++ break; ++ case 'l': ++ list++; ++ break; + case 'u': + keymask = UIDKEYS; + keystr = strdup(optarg); +@@ -273,28 +390,35 @@ int main(int argc, char **argv) + } + } + ++ if (geteuid() != 0) { ++ xlog_err("Must be run as root."); ++ return EXIT_FAILURE; ++ } ++ + if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF))) { + xlog_errno(rc, "Unable to create name to user id mappings."); +- return 1; ++ return EXIT_FAILURE; + } + if (!verbose) + verbose = conf_get_num("General", "Verbosity", 0); + ++ if (display) ++ return display_default_domain(); ++ if (list) ++ return list_keyring(DEFAULT_KEYRING); + if (keystr) { +- rc = key_invalidate(keystr, keymask); +- return rc; ++ return key_invalidate(keystr, keymask); + } + if (clearing) { + xlog_syslog(0); +- rc = keyring_clear(DEFAULT_KEYRING); +- return rc; ++ return keyring_clear(DEFAULT_KEYRING); + } + +- xlog_stderr(0); ++ xlog_stderr(verbose); + if ((argc - optind) != 2) { +- xlog_err("Bad arg count. Check /etc/request-key.conf"); ++ xlog_warn("Bad arg count. Check /etc/request-key.conf"); + xlog_warn(usage, progname); +- return 1; ++ return EXIT_FAILURE; + } + + if (verbose) +@@ -305,11 +429,15 @@ int main(int argc, char **argv) + arg = strdup(argv[optind]); + if (arg == NULL) { + xlog_err("strdup failed: %m"); +- return 1; ++ return EXIT_FAILURE; + } + type = strtok(arg, ":"); + value = strtok(NULL, ":"); +- ++ if (value == NULL) { ++ free(arg); ++ xlog_err("Error: Null uid/gid value."); ++ return EXIT_FAILURE; ++ } + if (verbose) { + xlog_warn("key: 0x%lx type: %s value: %s timeout %ld", + key, type, value, timeout); +@@ -328,7 +456,7 @@ int main(int argc, char **argv) + rc = name_lookup(value, key, GROUP); + + /* Set timeout to 10 (600 seconds) minutes */ +- if (rc == 0) ++ if (rc == EXIT_SUCCESS) + keyctl_set_timeout(key, timeout); + + free(arg); +diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man +index 3a3a523..0275bdf 100644 +--- a/utils/nfsidmap/nfsidmap.man ++++ b/utils/nfsidmap/nfsidmap.man +@@ -11,30 +11,72 @@ nfsidmap \- The NFS idmapper upcall program + .B "nfsidmap [-v] [-c]" + .br + .B "nfsidmap [-v] [-u|-g|-r user]" ++.br ++.B "nfsidmap -d" ++.br ++.B "nfsidmap -l" + .SH DESCRIPTION +-The file ++The NFSv4 protocol represents the local system's UID and GID values ++on the wire as strings of the form ++.IR user@domain . ++The process of translating from UID to string and string to UID is ++referred to as "ID mapping." ++.PP ++The system derives the ++.I user ++part of the string by performing a password or group lookup. ++The lookup mechanism is configured in ++.IR /etc/idmapd.conf . ++.PP ++By default, the ++.I domain ++part of the string is the system's DNS domain name. ++It can also be specified in ++.I /etc/idmapd.conf ++if the system is multi-homed, ++or if the system's DNS domain name does ++not match the name of the system's Kerberos realm. ++.PP ++The + .I /usr/sbin/nfsidmap +-is used by the NFS idmapper to translate user and group ids into names, and to +-translate user and group names into ids. Idmapper uses request-key to perform +-the upcall and cache the result. ++program performs translations on behalf of the kernel. ++The kernel uses the request-key mechanism to perform ++an upcall. + .I /usr/sbin/nfsidmap +-is called by /sbin/request-key, and will perform the translation and +-initialize a key with the resulting information. ++is invoked by /sbin/request-key, performs the translation, ++and initializes a key with the resulting information. ++The kernel then caches the translation results in the key. + .PP + .I nfsidmap +-can also used to clear the keyring of all the keys or +-revoke one particular key. +-This is useful when the id mappings have failed to due +-to a lookup error resulting in all the cached uids/gids to be set +-to the user id nobody. ++can also clear cached ID map results in the kernel, ++or revoke one particular key. ++An incorrect cached key can result in file and directory ownership ++reverting to "nobody" on NFSv4 mount points. ++.PP ++In addition, the ++.B -d ++and ++.B -l ++options are available to help diagnose misconfigurations. ++They have no effect on the keyring containing ID mapping results. + .SH OPTIONS + .TP + .B -c + Clear the keyring of all the keys. + .TP ++.B -d ++Display the system's effective NFSv4 domain name on ++.IR stdout . ++.TP + .B -g user + Revoke the gid key of the given user. + .TP ++.B -l ++Display on ++.I stdout ++all keys currently in the keyring used to cache ID mapping results. ++These keys are visible only to the superuser. ++.TP + .B -r user + Revoke both the uid and gid key of the given user. + .TP +@@ -89,5 +131,15 @@ Notice that the new line was added above the line for the generic program. + request-key will find the first matching line and run the corresponding program. + In this case, /some/other/program will handle all uid lookups, and + /usr/sbin/nfsidmap will handle gid, user, and group lookups. ++.SH FILES ++.TP ++.I /etc/idmapd.conf ++ID mapping configuration file ++.TP ++.I /etc/request-key.conf ++Request key configuration file ++.SH "SEE ALSO" ++.BR idmapd.conf (5), ++.BR request-key (8) + .SH AUTHOR + Bryan Schumaker, diff --git a/SOURCES/nfs-utils-1.3.0-nfsiostat-output.patch b/SOURCES/nfs-utils-1.3.0-nfsiostat-output.patch new file mode 100644 index 0000000..21c1642 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsiostat-output.patch @@ -0,0 +1,74 @@ +commit a4793601381656a64abe20ed8c2242f0eb2496e6 +Author: Jan Chaloupka +Date: Mon Jun 16 09:47:32 2014 -0400 + + nfsiostat: Document the output columns in the manpage + + Signed-off-by: Steve Dickson + +diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man +index 3ec245d..b477a9a 100644 +--- a/tools/nfs-iostat/nfsiostat.man ++++ b/tools/nfs-iostat/nfsiostat.man +@@ -38,6 +38,61 @@ If one or more + .I + names are specified, statistics for only these mount points will + be displayed. Otherwise, all NFS mount points on the client are listed. ++.TP ++The meaning of each column of \fBnfsiostat\fR's output is the following: ++.RS 8 ++- \fBop/s\fR ++.RS ++This is the number of operations per second. ++.RS ++.RE ++.RE ++.RE ++.RS 8 ++- \fBrpc bklog\fR ++.RS ++This is the length of the backlog queue. ++.RE ++.RE ++.RE ++.RS 8 ++- \fBkB/s\fR ++.RS ++This is the number of kB written/read per second. ++.RE ++.RE ++.RE ++.RS 8 ++- \fBkB/op\fR ++.RS ++This is the number of kB written/read per each operation. ++.RE ++.RE ++.RE ++.RS 8 ++- \fBretrans\fR ++.RS ++This is the number of retransmissions. ++.RE ++.RE ++.RE ++.RS 8 ++- \fBavg RTT (ms)\fR ++.RS ++This is the duration from the time that client's kernel sends the RPC request until the time it receives the reply. ++.RE ++.RE ++.RE ++.RS 8 ++- \fBavg exe (ms)\fR ++.RS ++This is the duration from the time that NFS client does the RPC request to its kernel until the RPC request is completed, this includes the RTT time above. ++.RE ++.RE ++.RE ++.TP ++Note that if an interval is used as argument to \fBnfsiostat\fR, then the diffrence from previous interval will be displayed, otherwise the results will be from the time that the share was mounted. ++ + .SH OPTIONS + .TP + .B \-a " or " \-\-attr diff --git a/SOURCES/nfs-utils-1.3.0-nfsman-minorversion.patch b/SOURCES/nfs-utils-1.3.0-nfsman-minorversion.patch new file mode 100644 index 0000000..7198acb --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsman-minorversion.patch @@ -0,0 +1,27 @@ +diff -up nfs-utils-1.3.0/utils/mount/nfs.man.orig nfs-utils-1.3.0/utils/mount/nfs.man +--- nfs-utils-1.3.0/utils/mount/nfs.man.orig 2017-03-31 16:15:33.487985468 -0400 ++++ nfs-utils-1.3.0/utils/mount/nfs.man 2017-03-31 16:30:21.321755420 -0400 +@@ -769,6 +769,23 @@ so if this mount option is not specified + uses the TCP protocol. + Refer to the TRANSPORT METHODS section for more details. + .TP 1.5i ++.BI minorversion= n ++Specifies the protocol minor version number. ++NFSv4 introduces "minor versioning," where NFS protocol enhancements can ++be introduced without bumping the NFS protocol version number. ++Before kernel 2.6.38, the minor version is always zero, and this ++option is not recognized. ++After this kernel, specifying "minorversion=1" enables a number of ++advanced features, such as NFSv4 sessions. ++.IP ++Recent kernels allow the minor version to be specified using the ++.B vers= ++option. ++For example, specifying ++.B vers=4.1 ++is the same as specifying ++.BR vers=4,minorversion=1 . ++.TP 1.5i + .BI port= n + The numeric value of the server's NFS service port. + If the server's NFS service is not available on the specified port, diff --git a/SOURCES/nfs-utils-1.3.0-nfsstat-mounts.patch b/SOURCES/nfs-utils-1.3.0-nfsstat-mounts.patch new file mode 100644 index 0000000..5cc704a --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsstat-mounts.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/utils/nfsstat/nfsstat.c.orig nfs-utils-1.3.0/utils/nfsstat/nfsstat.c +--- nfs-utils-1.3.0/utils/nfsstat/nfsstat.c.orig 2017-04-09 04:32:28.951729219 -0400 ++++ nfs-utils-1.3.0/utils/nfsstat/nfsstat.c 2017-04-09 04:34:49.686756801 -0400 +@@ -299,7 +299,7 @@ static struct option longopts[] = + { "all", 0, 0, 'v' }, + { "auto", 0, 0, '\3' }, + { "client", 0, 0, 'c' }, +- { "mounted", 0, 0, 'm' }, ++ { "mounts", 0, 0, 'm' }, + { "nfs", 0, 0, 'n' }, + { "rpc", 0, 0, 'r' }, + { "server", 0, 0, 's' }, diff --git a/SOURCES/nfs-utils-1.3.0-nfsstat-retval.patch b/SOURCES/nfs-utils-1.3.0-nfsstat-retval.patch new file mode 100644 index 0000000..0978d31 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-nfsstat-retval.patch @@ -0,0 +1,30 @@ +diff -up nfs-utils-1.3.0/utils/nfsstat/nfsstat.c.orig nfs-utils-1.3.0/utils/nfsstat/nfsstat.c +--- nfs-utils-1.3.0/utils/nfsstat/nfsstat.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/nfsstat/nfsstat.c 2017-03-29 12:10:52.820709442 -0400 +@@ -348,7 +348,7 @@ main(int argc, char **argv) + switch (c) { + case 'a': + fprintf(stderr, "nfsstat: nfs acls are not yet supported.\n"); +- return -1; ++ return 1; + case 'c': + opt_clt = 1; + break; +@@ -410,7 +410,7 @@ main(int argc, char **argv) + "not yet supported\n"); + return 2; + case 'm': +- return mounts(MOUNTSFILE); ++ return ! mounts(MOUNTSFILE); + case '\1': + usage(progname); + return 0; +@@ -419,7 +419,7 @@ main(int argc, char **argv) + return 0; + default: + printf("Try `%s --help' for more information.\n", progname); +- return -1; ++ return 1; + } + } + diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-acceptor.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-acceptor.patch new file mode 100644 index 0000000..ae82c69 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-acceptor.patch @@ -0,0 +1,398 @@ +diff -up nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig nfs-utils-1.3.0/utils/gssd/gssd_proc.c +--- nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig 2014-09-17 14:22:54.003055871 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd_proc.c 2014-09-17 14:36:02.917808209 -0400 +@@ -77,6 +77,7 @@ + #include "context.h" + #include "nfsrpc.h" + #include "nfslib.h" ++#include "gss_names.h" + + /* + * pollarray: +@@ -681,19 +682,25 @@ parse_enctypes(char *enctypes) + return 0; + } + +-static int ++static void + do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, +- gss_buffer_desc *context_token, OM_uint32 lifetime_rec) ++ gss_buffer_desc *context_token, OM_uint32 lifetime_rec, ++ gss_buffer_desc *acceptor) + { + char *buf = NULL, *p = NULL, *end = NULL; + unsigned int timeout = context_timeout; + unsigned int buf_size = 0; + +- printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec); ++ printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", ++ lifetime_rec, acceptor->length, acceptor->value); + buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + + sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + +- sizeof(context_token->length) + context_token->length; ++ sizeof(context_token->length) + context_token->length + ++ sizeof(acceptor->length) + acceptor->length; + p = buf = malloc(buf_size); ++ if (!buf) ++ goto out_err; ++ + end = buf + buf_size; + + /* context_timeout set by -t option overrides context lifetime */ +@@ -704,14 +711,15 @@ do_downcall(int k5_fd, uid_t uid, struct + if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err; + if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err; + if (write_buffer(&p, end, context_token)) goto out_err; ++ if (write_buffer(&p, end, acceptor)) goto out_err; + + if (write(k5_fd, buf, p - buf) < p - buf) goto out_err; +- if (buf) free(buf); +- return 0; ++ free(buf); ++ return; + out_err: +- if (buf) free(buf); ++ free(buf); + printerr(1, "Failed to write downcall!\n"); +- return -1; ++ return; + } + + static int +@@ -1035,6 +1043,9 @@ process_krb5_upcall(struct clnt_info *cl + gss_cred_id_t gss_cred; + OM_uint32 maj_stat, min_stat, lifetime_rec; + pid_t pid; ++ gss_name_t gacceptor = GSS_C_NO_NAME; ++ gss_OID mech; ++ gss_buffer_desc acceptor = {0}; + + pid = fork(); + switch(pid) { +@@ -1175,15 +1186,24 @@ process_krb5_upcall(struct clnt_info *cl + goto out_return_error; + } + +- /* Grab the context lifetime to pass to the kernel. lifetime_rec +- * is set to zero on error */ +- maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL, +- &lifetime_rec, NULL, NULL, NULL, NULL); +- +- if (maj_stat) +- printerr(1, "WARNING: Failed to inquire context for lifetme " +- "maj_stat %u\n", maj_stat); ++ /* Grab the context lifetime and acceptor name out of the ctx. */ ++ maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor, ++ &lifetime_rec, &mech, NULL, NULL, NULL); ++ ++ if (maj_stat != GSS_S_COMPLETE) { ++ printerr(1, "WARNING: Failed to inquire context " ++ "maj_stat (0x%x)\n", maj_stat); ++ lifetime_rec = 0; ++ } else { ++ get_hostbased_client_buffer(gacceptor, mech, &acceptor); ++ gss_release_name(&min_stat, &gacceptor); ++ } + ++ /* ++ * The serialization can mean turning pd.pd_ctx into a lucid context. If ++ * that happens then the pd.pd_ctx will be unusable, so we must never ++ * try to use it after this point. ++ */ + if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { + printerr(0, "WARNING: Failed to serialize krb5 context for " + "user with uid %d for server %s\n", +@@ -1191,9 +1211,10 @@ process_krb5_upcall(struct clnt_info *cl + goto out_return_error; + } + +- do_downcall(fd, uid, &pd, &token, lifetime_rec); ++ do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor); + + out: ++ gss_release_buffer(&min_stat, &acceptor); + if (token.value) + free(token.value); + #ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA +diff -up nfs-utils-1.3.0/utils/gssd/gss_names.c.orig nfs-utils-1.3.0/utils/gssd/gss_names.c +--- nfs-utils-1.3.0/utils/gssd/gss_names.c.orig 2014-09-17 14:35:16.646945303 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gss_names.c 2014-09-17 14:35:16.646945303 -0400 +@@ -0,0 +1,138 @@ ++/* ++ Copyright (c) 2000 The Regents of the University of Michigan. ++ All rights reserved. ++ ++ Copyright (c) 2002 Bruce Fields ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ 3. Neither the name of the University nor the names of its ++ contributors may be used to endorse or promote products derived ++ from this software without specific prior written permission. ++ ++ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif /* HAVE_CONFIG_H */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "svcgssd.h" ++#include "gss_util.h" ++#include "err_util.h" ++#include "context.h" ++#include "misc.h" ++#include "gss_oids.h" ++#include "svcgssd_krb5.h" ++ ++static int ++get_krb5_hostbased_name(gss_buffer_desc *name, char **hostbased_name) ++{ ++ char *p, *sname = NULL; ++ if (strchr(name->value, '@') && strchr(name->value, '/')) { ++ if ((sname = calloc(name->length, 1)) == NULL) { ++ printerr(0, "ERROR: get_krb5_hostbased_name failed " ++ "to allocate %d bytes\n", name->length); ++ return -1; ++ } ++ /* read in name and instance and replace '/' with '@' */ ++ sscanf(name->value, "%[^@]", sname); ++ p = strrchr(sname, '/'); ++ if (p == NULL) { /* The '@' preceeded the '/' */ ++ free(sname); ++ return -1; ++ } ++ *p = '@'; ++ } ++ *hostbased_name = sname; ++ return 0; ++} ++ ++int ++get_hostbased_client_name(gss_name_t client_name, gss_OID mech, ++ char **hostbased_name) ++{ ++ u_int32_t maj_stat, min_stat; ++ gss_buffer_desc name; ++ gss_OID name_type = GSS_C_NO_OID; ++ char *cname; ++ int res = -1; ++ ++ *hostbased_name = NULL; /* preset in case we fail */ ++ ++ /* Get the client's gss authenticated name */ ++ maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); ++ if (maj_stat != GSS_S_COMPLETE) { ++ pgsserr("get_hostbased_client_name: gss_display_name", ++ maj_stat, min_stat, mech); ++ goto out_err; ++ } ++ if (name.length >= 0xffff) { /* don't overflow */ ++ printerr(0, "ERROR: get_hostbased_client_name: " ++ "received gss_name is too long (%d bytes)\n", ++ name.length); ++ goto out_rel_buf; ++ } ++ ++ /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to ++ * an NT_HOSTBASED_SERVICE name */ ++ if (g_OID_equal(&krb5oid, mech)) { ++ if (get_krb5_hostbased_name(&name, &cname) == 0) ++ *hostbased_name = cname; ++ } else { ++ printerr(1, "WARNING: unknown/unsupport mech OID\n"); ++ } ++ ++ res = 0; ++out_rel_buf: ++ gss_release_buffer(&min_stat, &name); ++out_err: ++ return res; ++} ++ ++void ++get_hostbased_client_buffer(gss_name_t client_name, gss_OID mech, ++ gss_buffer_t buf) ++{ ++ char *hname; ++ ++ if (!get_hostbased_client_name(client_name, mech, &hname)) { ++ buf->length = strlen(hname) + 1; ++ buf->value = hname; ++ } else { ++ buf->length = 0; ++ buf->value = NULL; ++ } ++} +diff -up nfs-utils-1.3.0/utils/gssd/gss_names.h.orig nfs-utils-1.3.0/utils/gssd/gss_names.h +--- nfs-utils-1.3.0/utils/gssd/gss_names.h.orig 2014-09-17 14:35:16.646945303 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gss_names.h 2014-09-17 14:35:16.646945303 -0400 +@@ -0,0 +1,36 @@ ++/* ++ Copyright (c) 2000 The Regents of the University of Michigan. ++ All rights reserved. ++ ++ Copyright (c) 2002 Bruce Fields ++ ++ 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. ++*/ ++ ++extern int get_hostbased_client_name(gss_name_t client_name, gss_OID mech, ++ char **hostbased_name); ++extern void get_hostbased_client_buffer(gss_name_t client_name, ++ gss_OID mech, gss_buffer_t buf); +diff -up nfs-utils-1.3.0/utils/gssd/Makefile.am.orig nfs-utils-1.3.0/utils/gssd/Makefile.am +--- nfs-utils-1.3.0/utils/gssd/Makefile.am.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/Makefile.am 2014-09-17 14:35:16.645945284 -0400 +@@ -18,11 +18,13 @@ COMMON_SRCS = \ + context_lucid.c \ + gss_util.c \ + gss_oids.c \ ++ gss_names.c \ + err_util.c \ + \ + context.h \ + err_util.h \ + gss_oids.h \ ++ gss_names.h \ + gss_util.h + + gssd_SOURCES = \ +diff -up nfs-utils-1.3.0/utils/gssd/svcgssd_proc.c.orig nfs-utils-1.3.0/utils/gssd/svcgssd_proc.c +--- nfs-utils-1.3.0/utils/gssd/svcgssd_proc.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/svcgssd_proc.c 2014-09-17 14:35:16.646945303 -0400 +@@ -59,6 +59,7 @@ + #include "misc.h" + #include "gss_oids.h" + #include "svcgssd_krb5.h" ++#include "gss_names.h" + + extern char * mech2file(gss_OID mech); + #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" +@@ -315,71 +316,6 @@ print_hexl(const char *description, unsi + } + #endif + +-static int +-get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name) +-{ +- char *p, *sname = NULL; +- if (strchr(name->value, '@') && strchr(name->value, '/')) { +- if ((sname = calloc(name->length, 1)) == NULL) { +- printerr(0, "ERROR: get_krb5_hostbased_name failed " +- "to allocate %d bytes\n", name->length); +- return -1; +- } +- /* read in name and instance and replace '/' with '@' */ +- sscanf(name->value, "%[^@]", sname); +- p = strrchr(sname, '/'); +- if (p == NULL) { /* The '@' preceeded the '/' */ +- free(sname); +- return -1; +- } +- *p = '@'; +- } +- *hostbased_name = sname; +- return 0; +-} +- +-static int +-get_hostbased_client_name(gss_name_t client_name, gss_OID mech, +- char **hostbased_name) +-{ +- u_int32_t maj_stat, min_stat; +- gss_buffer_desc name; +- gss_OID name_type = GSS_C_NO_OID; +- char *cname; +- int res = -1; +- +- *hostbased_name = NULL; /* preset in case we fail */ +- +- /* Get the client's gss authenticated name */ +- maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); +- if (maj_stat != GSS_S_COMPLETE) { +- pgsserr("get_hostbased_client_name: gss_display_name", +- maj_stat, min_stat, mech); +- goto out_err; +- } +- if (name.length >= 0xffff) { /* don't overflow */ +- printerr(0, "ERROR: get_hostbased_client_name: " +- "received gss_name is too long (%d bytes)\n", +- name.length); +- goto out_rel_buf; +- } +- +- /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to +- * an NT_HOSTBASED_SERVICE name */ +- if (g_OID_equal(&krb5oid, mech)) { +- if (get_krb5_hostbased_name(&name, &cname) == 0) +- *hostbased_name = cname; +- } else { +- printerr(1, "WARNING: unknown/unsupport mech OID\n"); +- } +- +- res = 0; +-out_rel_buf: +- gss_release_buffer(&min_stat, &name); +-out_err: +- return res; +-} +- + void + handle_nullreq(FILE *f) { + /* XXX initialize to a random integer to reduce chances of unnecessary diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-debug.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-debug.patch new file mode 100644 index 0000000..656854b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-debug.patch @@ -0,0 +1,2564 @@ +diff -up nfs-utils-1.3.0/aclocal/libtirpc.m4.orig nfs-utils-1.3.0/aclocal/libtirpc.m4 +--- nfs-utils-1.3.0/aclocal/libtirpc.m4.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/aclocal/libtirpc.m4 2016-04-15 11:42:49.532156526 -0400 +@@ -2,61 +2,61 @@ dnl Checks for TI-RPC library and header + dnl + AC_DEFUN([AC_LIBTIRPC], [ + ++ AS_IF( ++ [test "$enable_tirpc" != "no"], ++ [PKG_CHECK_MODULES([TIRPC], [libtirpc], ++ [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.])], ++ [AC_LIBTIRPC_OLD ++ AS_IF([test "$enable_tirpc" = "yes" -a -z "${LIBTIRPC}"], ++ [AC_MSG_ERROR([libtirpc not found.])])])]) ++ ++ AS_IF([test -n "${LIBTIRPC}"], ++ [AC_CHECK_LIB([tirpc], [authgss_free_private_data], ++ [AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], [1], ++ [Define to 1 if your rpcsec library provides authgss_free_private_data])],, ++ [${LIBS}])]) ++ ++ AS_IF([test -n "${LIBTIRPC}"], ++ [AC_CHECK_LIB([tirpc], [libtirpc_set_debug], ++ [AC_DEFINE([HAVE_LIBTIRPC_SET_DEBUG], [1], ++ [Define to 1 if your tirpc library provides libtirpc_set_debug])],, ++ [${LIBS}])]) ++ ++ AC_SUBST([AM_CPPFLAGS]) ++ AC_SUBST(LIBTIRPC) ++ ++])dnl ++ ++dnl Old way of checking libtirpc without pkg-config ++dnl This can go away when virtually all libtirpc provide a .pc file ++dnl ++AC_DEFUN([AC_LIBTIRPC_OLD], [ ++ + 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 +- +- AC_SUBST(LIBTIRPC) ++ dnl Look for the library ++ AC_CHECK_LIB([tirpc], [clnt_tli_create], ++ [has_libtirpc="yes"], ++ [has_libtirpc="no"]) ++ ++ dnl Also must have the headers installed where we expect ++ dnl to look for headers; add -I compiler option if found ++ AS_IF([test "$has_libtirpc" = "yes"], ++ [AC_CHECK_HEADERS([${tirpc_header_dir}/netconfig.h], ++ [AC_SUBST([AM_CPPFLAGS], ["-I${tirpc_header_dir}"])], ++ [has_libtirpc="no"])]) ++ ++ dnl Now set $LIBTIRPC accordingly ++ AS_IF([test "$has_libtirpc" = "yes"], ++ [AC_DEFINE([HAVE_LIBTIRPC], [1], ++ [Define to 1 if you have and wish to use libtirpc.]) ++ LIBTIRPC="-ltirpc"]) + + ])dnl +diff -up nfs-utils-1.3.0/support/include/nfslib.h.orig nfs-utils-1.3.0/support/include/nfslib.h +--- nfs-utils-1.3.0/support/include/nfslib.h.orig 2016-04-15 11:42:13.930460892 -0400 ++++ nfs-utils-1.3.0/support/include/nfslib.h 2016-04-15 11:42:38.365938345 -0400 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -129,8 +130,8 @@ void fendrmtabent(FILE *fp); + void frewindrmtabent(FILE *fp); + + /* mydaemon */ +-void mydaemon(int nochdir, int noclose, int *pipefds); +-void release_parent(int *pipefds); ++void daemon_init(bool fg); ++void daemon_ready(void); + + /* + * wildmat borrowed from INN +@@ -182,6 +183,9 @@ size_t strlcpy(char *, const char *, si + ssize_t atomicio(ssize_t (*f) (int, void*, size_t), + int, void *, size_t); + ++#ifdef HAVE_LIBTIRPC_SET_DEBUG ++void libtirpc_set_debug(char *name, int level, int use_stderr); ++#endif + + #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) + +diff -up nfs-utils-1.3.0/support/nfs/mydaemon.c.orig nfs-utils-1.3.0/support/nfs/mydaemon.c +--- nfs-utils-1.3.0/support/nfs/mydaemon.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nfs/mydaemon.c 2016-04-15 11:42:38.366938365 -0400 +@@ -46,56 +46,61 @@ + #include + #include + #include ++#include + #include + #include + #include + ++#include "nfslib.h" ++ ++static int pipefds[2] = { -1, -1}; ++ + /** +- * 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 ++ * daemon_init - initial daemon setup ++ * @fg: whether to run in the foreground + * + * 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. ++ * child dies or writes an int on the pipe signaling its status. + */ + void +-mydaemon(int nochdir, int noclose, int *pipefds) ++daemon_init(bool fg) + { + int pid, status, tempfd; + ++ if (fg) ++ return; ++ + if (pipe(pipefds) < 0) { + xlog_err("mydaemon: pipe() failed: errno %d (%s)\n", + errno, strerror(errno)); +- exit(1); ++ exit(EXIT_FAILURE); + } +- if ((pid = fork ()) < 0) { ++ ++ pid = fork(); ++ if (pid < 0) { + xlog_err("mydaemon: fork() failed: errno %d (%s)\n", + errno, strerror(errno)); +- exit(1); ++ exit(EXIT_FAILURE); + } + +- if (pid != 0) { +- /* +- * Parent. Wait for status from child. +- */ ++ if (pid > 0) { ++ /* Parent */ + close(pipefds[1]); +- if (read(pipefds[0], &status, 1) != 1) +- exit(1); +- exit (0); ++ if (read(pipefds[0], &status, sizeof(status)) != sizeof(status)) ++ exit(EXIT_FAILURE); ++ exit(status); + } +- /* Child. */ ++ ++ /* 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); +- } ++ ++ if (chdir ("/")) { ++ xlog_err("mydaemon: chdir() failed: errno %d (%s)\n", ++ errno, strerror(errno)); ++ exit(EXIT_FAILURE); + } + + while (pipefds[1] <= 2) { +@@ -103,41 +108,39 @@ mydaemon(int nochdir, int noclose, int * + if (pipefds[1] < 0) { + xlog_err("mydaemon: dup() failed: errno %d (%s)\n", + errno, strerror(errno)); +- exit(1); ++ exit(EXIT_FAILURE); + } + } + +- 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); +- } ++ tempfd = open("/dev/null", O_RDWR); ++ if (tempfd < 0) { ++ xlog_err("mydaemon: can't open /dev/null: errno %d " ++ "(%s)\n", errno, strerror(errno)); ++ exit(EXIT_FAILURE); + } + +- return; ++ dup2(tempfd, 0); ++ dup2(tempfd, 1); ++ dup2(tempfd, 2); ++ closelog(); ++ dup2(pipefds[1], 3); ++ pipefds[1] = 3; ++ closeall(4); + } + + /** +- * release_parent - tell the parent that it can exit now +- * @pipefds: pipefd array that was previously passed to mydaemon() ++ * daemon_ready - tell interested parties that the daemon is ready + * +- * This function tells the parent process of mydaemon() that it's now clear +- * to exit(0). ++ * This function tells e.g. the parent process that the daemon is up ++ * and running. + */ + void +-release_parent(int *pipefds) ++daemon_ready(void) + { +- int status; ++ int status = 0; + + if (pipefds[1] > 0) { +- if (write(pipefds[1], &status, 1) != 1) { ++ if (write(pipefds[1], &status, sizeof(status)) != sizeof(status)) { + xlog_err("WARN: writing to parent pipe failed: errno " + "%d (%s)\n", errno, strerror(errno)); + } +diff -up nfs-utils-1.3.0/support/nfs/svc_create.c.orig nfs-utils-1.3.0/support/nfs/svc_create.c +--- nfs-utils-1.3.0/support/nfs/svc_create.c.orig 2016-04-15 11:42:13.931460911 -0400 ++++ nfs-utils-1.3.0/support/nfs/svc_create.c 2016-04-15 11:42:38.366938365 -0400 +@@ -133,7 +133,7 @@ svc_create_bindaddr(struct netconfig *nc + hint.ai_family = AF_INET6; + #endif /* IPV6_SUPPORTED */ + else { +- xlog(D_GENERAL, "Unrecognized bind address family: %s", ++ xlog(L_ERROR, "Unrecognized bind address family: %s", + nconf->nc_protofmly); + return NULL; + } +@@ -143,7 +143,7 @@ svc_create_bindaddr(struct netconfig *nc + else if (strcmp(nconf->nc_proto, NC_TCP) == 0) + hint.ai_protocol = (int)IPPROTO_TCP; + else { +- xlog(D_GENERAL, "Unrecognized bind address protocol: %s", ++ xlog(L_ERROR, "Unrecognized bind address protocol: %s", + nconf->nc_proto); + return NULL; + } +@@ -275,7 +275,7 @@ svc_create_nconf_rand_port(const char *n + xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0); + freeaddrinfo(ai); + if (xprt == NULL) { +- xlog(D_GENERAL, "Failed to create listener xprt " ++ xlog(L_ERROR, "Failed to create listener xprt " + "(%s, %u, %s)", name, version, nconf->nc_netid); + return 0; + } +@@ -286,10 +286,12 @@ svc_create_nconf_rand_port(const char *n + return 0; + } + ++ rpc_createerr.cf_stat = rpc_createerr.cf_error.re_errno = 0; + if (!svc_reg(xprt, program, version, dispatch, nconf)) { + /* svc_reg(3) destroys @xprt in this case */ +- xlog(D_GENERAL, "Failed to register (%s, %u, %s)", +- name, version, nconf->nc_netid); ++ xlog(L_ERROR, "Failed to register (%s, %u, %s): %s", ++ name, version, nconf->nc_netid, ++ clnt_spcreateerror("svc_reg() err")); + return 0; + } + +diff -up nfs-utils-1.3.0/support/nfs/svc_socket.c.orig nfs-utils-1.3.0/support/nfs/svc_socket.c +--- nfs-utils-1.3.0/support/nfs/svc_socket.c.orig 2016-04-15 11:42:13.931460911 -0400 ++++ nfs-utils-1.3.0/support/nfs/svc_socket.c 2016-04-15 11:42:38.367938385 -0400 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include "xlog.h" + + #ifdef _LIBC + # include +@@ -90,9 +91,9 @@ svcsock_nonblock(int sock) + * connection. + */ + if ((flags = fcntl(sock, F_GETFL)) < 0) +- perror(_("svc_socket: can't get socket flags")); ++ xlog(L_ERROR, "svc_socket: can't get socket flags: %m"); + else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) +- perror(_("svc_socket: can't set socket flags")); ++ xlog(L_ERROR, "svc_socket: can't set socket flags: %m"); + else + return sock; + +@@ -110,7 +111,7 @@ svc_socket (u_long number, int type, int + + if ((sock = __socket (AF_INET, type, protocol)) < 0) + { +- perror (_("svc_socket: socket creation problem")); ++ xlog(L_ERROR, "svc_socket: socket creation problem: %m"); + return sock; + } + +@@ -121,7 +122,7 @@ svc_socket (u_long number, int type, int + sizeof (ret)); + if (ret < 0) + { +- perror (_("svc_socket: socket reuse problem")); ++ xlog(L_ERROR, "svc_socket: socket reuse problem: %m"); + return ret; + } + } +@@ -132,7 +133,7 @@ svc_socket (u_long number, int type, int + + if (bind(sock, (struct sockaddr *) &addr, len) < 0) + { +- perror (_("svc_socket: bind problem")); ++ xlog(L_ERROR, "svc_socket: bind problem: %m"); + (void) __close(sock); + sock = -1; + } +diff -up nfs-utils-1.3.0/utils/gssd/context_heimdal.c.orig nfs-utils-1.3.0/utils/gssd/context_heimdal.c +--- nfs-utils-1.3.0/utils/gssd/context_heimdal.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/context_heimdal.c 2016-04-15 11:42:38.367938385 -0400 +@@ -260,7 +260,7 @@ serialize_krb5_ctx(gss_ctx_id_t *_ctx, g + if (write_heimdal_seq_key(&p, end, ctx)) goto out_err; + + buf->length = p - (char *)buf->value; +- printerr(2, "serialize_krb5_ctx: returning buffer " ++ printerr(4, "serialize_krb5_ctx: returning buffer " + "with %d bytes\n", buf->length); + + return 0; +diff -up nfs-utils-1.3.0/utils/gssd/context_lucid.c.orig nfs-utils-1.3.0/utils/gssd/context_lucid.c +--- nfs-utils-1.3.0/utils/gssd/context_lucid.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/context_lucid.c 2016-04-15 11:42:38.367938385 -0400 +@@ -206,7 +206,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc + if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; + + /* Protocol 0 here implies DES3 or RC4 */ +- printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); ++ printerr(4, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); + if (lctx->protocol == 0) { + enctype = lctx->rfc1964_kd.ctx_key.type; + keysize = lctx->rfc1964_kd.ctx_key.length; +@@ -219,7 +219,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc + keysize = lctx->cfx_kd.ctx_key.length; + } + } +- printerr(2, "%s: serializing key with enctype %d and size %d\n", ++ printerr(4, "%s: serializing key with enctype %d and size %d\n", + __FUNCTION__, enctype, keysize); + + if (WRITE_BYTES(&p, end, enctype)) goto out_err; +@@ -265,7 +265,7 @@ serialize_krb5_ctx(gss_ctx_id_t *ctx, gs + gss_krb5_lucid_context_v1_t *lctx = 0; + int retcode = 0; + +- printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); ++ printerr(4, "DEBUG: %s: lucid version!\n", __FUNCTION__); + maj_stat = gss_export_lucid_sec_context(&min_stat, ctx, + 1, &return_ctx); + if (maj_stat != GSS_S_COMPLETE) { +diff -up nfs-utils-1.3.0/utils/gssd/gssd.c.orig nfs-utils-1.3.0/utils/gssd/gssd.c +--- nfs-utils-1.3.0/utils/gssd/gssd.c.orig 2016-04-15 11:42:13.917460638 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.c 2016-04-15 11:42:38.369938424 -0400 +@@ -1,7 +1,7 @@ + /* + gssd.c + +- Copyright (c) 2000 The Regents of the University of Michigan. ++ Copyright (c) 2000, 2004 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . +@@ -40,9 +40,18 @@ + #include + #endif /* HAVE_CONFIG_H */ + ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++ + #include + #include ++#include ++#include ++#include + #include ++#include ++#include + + #include + #include +@@ -51,41 +60,684 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include ++ + #include "gssd.h" + #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; +-char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR ":" GSSD_USER_CRED_DIR; +-char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1]; ++static char *pipefs_path = GSSD_PIPEFS_DIR; ++static DIR *pipefs_dir; ++static int pipefs_fd; ++static int inotify_fd; ++struct event inotify_ev; ++ ++char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; ++char **ccachesearch; + int use_memcache = 0; + int root_uses_machine_creds = 1; + unsigned int context_timeout = 0; + unsigned int rpc_timeout = 5; + char *preferred_realm = NULL; +-int pipefds[2] = { -1, -1 }; ++/* Avoid DNS reverse lookups on server names */ ++static bool avoid_dns = true; ++ ++ ++TAILQ_HEAD(topdir_list_head, topdir) topdir_list; ++ ++struct topdir { ++ TAILQ_ENTRY(topdir) list; ++ TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; ++ int wd; ++ char name[]; ++}; ++ ++/* ++ * topdir_list: ++ * linked list of struct topdir with basic data about a topdir. ++ * ++ * clnt_list: ++ * linked list of struct clnt_info with basic data about a clntXXX dir, ++ * one per topdir. ++ * ++ * Directory structure: created by the kernel ++ * {rpc_pipefs}/{topdir}/clntXX : one per rpc_clnt struct in the kernel ++ * {rpc_pipefs}/{topdir}/clntXX/krb5 : read uid for which kernel wants ++ * a context, write the resulting context ++ * {rpc_pipefs}/{topdir}/clntXX/info : stores info such as server name ++ * {rpc_pipefs}/{topdir}/clntXX/gssd : pipe for all gss mechanisms using ++ * a text-based string of parameters ++ * ++ * Algorithm: ++ * Poll all {rpc_pipefs}/{topdir}/clntXX/YYYY files. When data is ready, ++ * read and process; performs rpcsec_gss context initialization protocol to ++ * get a cred for that user. Writes result to corresponding krb5 file ++ * in a form the kernel code will understand. ++ * In addition, we make sure we are notified whenever anything is ++ * created or destroyed in {rpc_pipefs} or in any of the clntXX directories, ++ * and rescan the whole {rpc_pipefs} when this happens. ++ */ ++ ++/* ++ * convert a presentation address string to a sockaddr_storage struct. Returns ++ * true on success or false on failure. ++ * ++ * Note that we do not populate the sin6_scope_id field here for IPv6 addrs. ++ * gssd nececessarily relies on hostname resolution and DNS AAAA records ++ * do not generally contain scope-id's. This means that GSSAPI auth really ++ * can't work with IPv6 link-local addresses. ++ * ++ * We *could* consider changing this if we did something like adopt the ++ * Microsoft "standard" of using the ipv6-literal.net domainname, but it's ++ * not really feasible at present. ++ */ ++static bool ++gssd_addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port) ++{ ++ int rc; ++ struct addrinfo *res; ++ struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV }; ++ ++#ifndef IPV6_SUPPORTED ++ hints.ai_family = AF_INET; ++#endif /* IPV6_SUPPORTED */ ++ ++ rc = getaddrinfo(node, port, &hints, &res); ++ if (rc) { ++ printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n", ++ node, port, ++ rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc)); ++ return false; ++ } ++ ++#ifdef IPV6_SUPPORTED ++ /* ++ * getnameinfo ignores the scopeid. If the address turns out to have ++ * a non-zero scopeid, we can't use it -- the resolved host might be ++ * completely different from the one intended. ++ */ ++ if (res->ai_addr->sa_family == AF_INET6) { ++ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr; ++ if (sin6->sin6_scope_id) { ++ printerr(0, "ERROR: address %s has non-zero " ++ "sin6_scope_id!\n", node); ++ freeaddrinfo(res); ++ return false; ++ } ++ } ++#endif /* IPV6_SUPPORTED */ ++ ++ memcpy(sa, res->ai_addr, res->ai_addrlen); ++ freeaddrinfo(res); ++ return true; ++} ++ ++/* ++ * convert a sockaddr to a hostname ++ */ ++static char * ++gssd_get_servername(const char *name, const struct sockaddr *sa, const char *addr) ++{ ++ socklen_t addrlen; ++ int err; ++ char hbuf[NI_MAXHOST]; ++ unsigned char buf[sizeof(struct in6_addr)]; ++ ++ while (avoid_dns) { ++ /* ++ * Determine if this is a server name, or an IP address. ++ * If it is an IP address, do the DNS lookup otherwise ++ * skip the DNS lookup. ++ */ ++ if (strchr(name, '.') == NULL) ++ break; /* local name */ ++ else if (inet_pton(AF_INET, name, buf) == 1) ++ break; /* IPv4 address */ ++ else if (inet_pton(AF_INET6, name, buf) == 1) ++ break; /* IPv6 addrss */ ++ ++ return strdup(name); ++ } ++ ++ switch (sa->sa_family) { ++ case AF_INET: ++ addrlen = sizeof(struct sockaddr_in); ++ break; ++#ifdef IPV6_SUPPORTED ++ case AF_INET6: ++ addrlen = sizeof(struct sockaddr_in6); ++ break; ++#endif /* IPV6_SUPPORTED */ ++ default: ++ printerr(0, "ERROR: unrecognized addr family %d\n", ++ sa->sa_family); ++ return NULL; ++ } ++ ++ err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0, ++ NI_NAMEREQD); ++ if (err) { ++ printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", ++ addr, err == EAI_SYSTEM ? strerror(errno) : ++ gai_strerror(err)); ++ return NULL; ++ } ++ ++ return strdup(hbuf); ++} ++ ++static void ++gssd_read_service_info(int dirfd, struct clnt_info *clp) ++{ ++ int fd; ++ FILE *info = NULL; ++ int numfields; ++ char *server = NULL; ++ char *service = NULL; ++ int program; ++ int version; ++ char *address = NULL; ++ char *protoname = NULL; ++ char *port = NULL; ++ char *servername = NULL; ++ ++ fd = openat(dirfd, "info", O_RDONLY); ++ if (fd < 0) { ++ printerr(0, "ERROR: can't open %s/info: %s\n", ++ clp->relpath, strerror(errno)); ++ goto fail; ++ } ++ ++ info = fdopen(fd, "r"); ++ if (!info) { ++ printerr(0, "ERROR: can't fdopen %s/info: %s\n", ++ clp->relpath, strerror(errno)); ++ close(fd); ++ goto fail; ++ } ++ ++ /* ++ * Some history: ++ * ++ * The first three lines were added with rpc_pipefs in 2003-01-13. ++ * (commit af2f003391786fb632889c02142c941b212ba4ff) ++ * ++ * The 'protocol' line was added in 2003-06-11. ++ * (commit 9bd741ae48785d0c0e75cf906ff66f893d600c2d) ++ * ++ * The 'port' line was added in 2007-09-26. ++ * (commit bf19aacecbeebccb2c3d150a8bd9416b7dba81fe) ++ */ ++ numfields = fscanf(info, ++ "RPC server: %ms\n" ++ "service: %ms (%d) version %d\n" ++ "address: %ms\n" ++ "protocol: %ms\n" ++ "port: %ms\n", ++ &server, ++ &service, &program, &version, ++ &address, ++ &protoname, ++ &port); ++ ++ ++ switch (numfields) { ++ case 5: ++ protoname = strdup("tcp"); ++ if (!protoname) ++ goto fail; ++ /* fall through */ ++ case 6: ++ /* fall through */ ++ case 7: ++ break; ++ default: ++ goto fail; ++ } ++ ++ if (!gssd_addrstr_to_sockaddr((struct sockaddr *)&clp->addr, ++ address, port ? port : "")) ++ goto fail; ++ ++ servername = gssd_get_servername(server, (struct sockaddr *)&clp->addr, address); ++ if (!servername) ++ goto fail; ++ ++ if (asprintf(&clp->servicename, "%s@%s", service, servername) < 0) ++ goto fail; ++ ++ clp->servername = servername; ++ clp->prog = program; ++ clp->vers = version; ++ clp->protocol = protoname; ++ ++ goto out; ++ ++fail: ++ printerr(0, "ERROR: failed to parse %s/info\n", clp->relpath); ++ free(servername); ++ free(protoname); ++ clp->servicename = NULL; ++ clp->servername = NULL; ++ clp->prog = 0; ++ clp->vers = 0; ++ clp->protocol = NULL; ++out: ++ if (info) ++ fclose(info); ++ ++ free(server); ++ free(service); ++ free(address); ++ free(port); ++} ++ ++static void ++gssd_destroy_client(struct clnt_info *clp) ++{ ++ if (clp->krb5_fd >= 0) { ++ close(clp->krb5_fd); ++ event_del(&clp->krb5_ev); ++ } ++ ++ if (clp->gssd_fd >= 0) { ++ close(clp->gssd_fd); ++ event_del(&clp->gssd_ev); ++ } ++ ++ inotify_rm_watch(inotify_fd, clp->wd); ++ free(clp->relpath); ++ free(clp->servicename); ++ free(clp->servername); ++ free(clp->protocol); ++ free(clp); ++} ++ ++static void gssd_scan(void); ++ ++static void ++gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) ++{ ++ struct clnt_info *clp = data; ++ ++ handle_gssd_upcall(clp); ++} ++ ++static void ++gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) ++{ ++ struct clnt_info *clp = data; ++ ++ handle_krb5_upcall(clp); ++} ++ ++static struct clnt_info * ++gssd_get_clnt(struct topdir *tdi, const char *name) ++{ ++ struct clnt_info *clp; ++ ++ TAILQ_FOREACH(clp, &tdi->clnt_list, list) ++ if (!strcmp(clp->name, name)) ++ return clp; ++ ++ clp = calloc(1, sizeof(struct clnt_info)); ++ if (!clp) { ++ printerr(0, "ERROR: can't malloc clnt_info: %s\n", ++ strerror(errno)); ++ return NULL; ++ } ++ ++ if (asprintf(&clp->relpath, "%s/%s", tdi->name, name) < 0) { ++ clp->relpath = NULL; ++ goto out; ++ } ++ ++ clp->wd = inotify_add_watch(inotify_fd, clp->relpath, IN_CREATE | IN_DELETE); ++ if (clp->wd < 0) { ++ if (errno != ENOENT) ++ printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n", ++ clp->relpath, strerror(errno)); ++ goto out; ++ } ++ ++ clp->name = clp->relpath + strlen(tdi->name) + 1; ++ clp->krb5_fd = -1; ++ clp->gssd_fd = -1; ++ ++ TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list); ++ return clp; ++ ++out: ++ free(clp->relpath); ++ free(clp); ++ return NULL; ++} ++ ++static int ++gssd_scan_clnt(struct clnt_info *clp) ++{ ++ int clntfd; ++ bool gssd_was_closed; ++ bool krb5_was_closed; ++ ++ gssd_was_closed = clp->gssd_fd < 0 ? true : false; ++ krb5_was_closed = clp->krb5_fd < 0 ? true : false; ++ ++ clntfd = openat(pipefs_fd, clp->relpath, O_RDONLY); ++ if (clntfd < 0) { ++ printerr(0, "ERROR: can't openat %s: %s\n", ++ clp->relpath, strerror(errno)); ++ return -1; ++ } ++ ++ if (clp->gssd_fd == -1) ++ clp->gssd_fd = openat(clntfd, "gssd", O_RDWR | O_NONBLOCK); ++ ++ if (clp->gssd_fd == -1 && clp->krb5_fd == -1) ++ clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK); ++ ++ if (gssd_was_closed && clp->gssd_fd >= 0) { ++ event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST, ++ gssd_clnt_gssd_cb, clp); ++ event_add(&clp->gssd_ev, NULL); ++ } ++ ++ if (krb5_was_closed && clp->krb5_fd >= 0) { ++ event_set(&clp->krb5_ev, clp->krb5_fd, EV_READ | EV_PERSIST, ++ gssd_clnt_krb5_cb, clp); ++ event_add(&clp->krb5_ev, NULL); ++ } ++ ++ if (clp->krb5_fd == -1 && clp->gssd_fd == -1) ++ /* not fatal, files might appear later */ ++ goto out; ++ ++ if (clp->prog == 0) ++ gssd_read_service_info(clntfd, clp); ++ ++out: ++ close(clntfd); ++ clp->scanned = true; ++ return 0; ++} ++ ++static int ++gssd_create_clnt(struct topdir *tdi, const char *name) ++{ ++ struct clnt_info *clp; ++ ++ clp = gssd_get_clnt(tdi, name); ++ if (!clp) ++ return -1; ++ ++ return gssd_scan_clnt(clp); ++} + +-void ++static struct topdir * ++gssd_get_topdir(const char *name) ++{ ++ struct topdir *tdi; ++ ++ TAILQ_FOREACH(tdi, &topdir_list, list) ++ if (!strcmp(tdi->name, name)) ++ return tdi; ++ ++ tdi = malloc(sizeof(*tdi) + strlen(name) + 1); ++ if (!tdi) { ++ printerr(0, "ERROR: Couldn't allocate struct topdir\n"); ++ return NULL; ++ } ++ ++ tdi->wd = inotify_add_watch(inotify_fd, name, IN_CREATE); ++ if (tdi->wd < 0) { ++ printerr(0, "ERROR: inotify_add_watch failed for top dir %s: %s\n", ++ tdi->name, strerror(errno)); ++ free(tdi); ++ return NULL; ++ } ++ ++ strcpy(tdi->name, name); ++ TAILQ_INIT(&tdi->clnt_list); ++ ++ TAILQ_INSERT_HEAD(&topdir_list, tdi, list); ++ return tdi; ++} ++ ++static void ++gssd_scan_topdir(const char *name) ++{ ++ struct topdir *tdi; ++ int dfd; ++ DIR *dir; ++ struct clnt_info *clp; ++ struct dirent *d; ++ ++ tdi = gssd_get_topdir(name); ++ if (!tdi) ++ return; ++ ++ dfd = openat(pipefs_fd, tdi->name, O_RDONLY); ++ if (dfd < 0) { ++ printerr(0, "ERROR: can't openat %s: %s\n", ++ tdi->name, strerror(errno)); ++ return; ++ } ++ ++ dir = fdopendir(dfd); ++ if (!dir) { ++ printerr(0, "ERROR: can't fdopendir %s: %s\n", ++ tdi->name, strerror(errno)); ++ return; ++ } ++ ++ TAILQ_FOREACH(clp, &tdi->clnt_list, list) ++ clp->scanned = false; ++ ++ while ((d = readdir(dir))) { ++ if (d->d_type != DT_DIR) ++ continue; ++ ++ if (strncmp(d->d_name, "clnt", strlen("clnt"))) ++ continue; ++ ++ gssd_create_clnt(tdi, d->d_name); ++ } ++ ++ closedir(dir); ++ ++ TAILQ_FOREACH(clp, &tdi->clnt_list, list) { ++ void *saveprev; ++ ++ if (clp->scanned) ++ continue; ++ ++ printerr(3, "destroying client %s\n", clp->relpath); ++ saveprev = clp->list.tqe_prev; ++ TAILQ_REMOVE(&tdi->clnt_list, clp, list); ++ gssd_destroy_client(clp); ++ clp = saveprev; ++ } ++} ++ ++static void ++gssd_scan(void) ++{ ++ struct dirent *d; ++ ++ printerr(3, "doing a full rescan\n"); ++ rewinddir(pipefs_dir); ++ ++ while ((d = readdir(pipefs_dir))) { ++ if (d->d_type != DT_DIR) ++ continue; ++ ++ if (d->d_name[0] == '.') ++ continue; ++ ++ gssd_scan_topdir(d->d_name); ++ } ++ ++ if (TAILQ_EMPTY(&topdir_list)) { ++ printerr(0, "ERROR: the rpc_pipefs directory is empty!\n"); ++ exit(EXIT_FAILURE); ++ } ++} ++ ++static void ++gssd_scan_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) ++{ ++ gssd_scan(); ++} ++ ++static bool ++gssd_inotify_topdir(struct topdir *tdi, const struct inotify_event *ev) ++{ ++ printerr(5, "inotify event for topdir (%s) - " ++ "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", ++ tdi->name, ev->wd, ev->len > 0 ? ev->name : "", ev->mask); ++ ++ if (ev->mask & IN_IGNORED) { ++ printerr(0, "ERROR: topdir disappeared!\n"); ++ return false; ++ } ++ ++ if (ev->len == 0) ++ return false; ++ ++ if (ev->mask & IN_CREATE) { ++ if (!(ev->mask & IN_ISDIR)) ++ return true; ++ ++ if (strncmp(ev->name, "clnt", strlen("clnt"))) ++ return true; ++ ++ if (gssd_create_clnt(tdi, ev->name)) ++ return false; ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool ++gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotify_event *ev) ++{ ++ printerr(5, "inotify event for clntdir (%s) - " ++ "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", ++ clp->relpath, ev->wd, ev->len > 0 ? ev->name : "", ev->mask); ++ ++ if (ev->mask & IN_IGNORED) { ++ TAILQ_REMOVE(&tdi->clnt_list, clp, list); ++ gssd_destroy_client(clp); ++ return true; ++ } ++ ++ if (ev->len == 0) ++ return false; ++ ++ if (ev->mask & IN_CREATE) { ++ if (!strcmp(ev->name, "gssd") || ++ !strcmp(ev->name, "krb5") || ++ !strcmp(ev->name, "info")) ++ if (gssd_scan_clnt(clp)) ++ return false; ++ ++ return true; ++ ++ } else if (ev->mask & IN_DELETE) { ++ if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) { ++ close(clp->gssd_fd); ++ event_del(&clp->gssd_ev); ++ clp->gssd_fd = -1; ++ ++ } else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) { ++ close(clp->krb5_fd); ++ event_del(&clp->krb5_ev); ++ clp->krb5_fd = -1; ++ } ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data)) ++{ ++ bool rescan = false; ++ struct topdir *tdi; ++ struct clnt_info *clp; ++ ++ while (true) { ++ char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); ++ const struct inotify_event *ev; ++ ssize_t len; ++ char *ptr; ++ ++ len = read(ifd, buf, sizeof(buf)); ++ if (len == -1 && errno == EINTR) ++ continue; ++ ++ if (len <= 0) ++ break; ++ ++ for (ptr = buf; ptr < buf + len; ++ ptr += sizeof(struct inotify_event) + ev->len) { ++ ev = (const struct inotify_event *)ptr; ++ ++ if (ev->mask & IN_Q_OVERFLOW) { ++ printerr(0, "ERROR: inotify queue overflow\n"); ++ rescan = true; ++ break; ++ } ++ ++ TAILQ_FOREACH(tdi, &topdir_list, list) { ++ if (tdi->wd == ev->wd) { ++ if (!gssd_inotify_topdir(tdi, ev)) ++ rescan = true; ++ goto found; ++ } ++ ++ TAILQ_FOREACH(clp, &tdi->clnt_list, list) { ++ if (clp->wd == ev->wd) { ++ if (!gssd_inotify_clnt(tdi, clp, ev)) ++ rescan = true; ++ goto found; ++ } ++ } ++ } ++ ++found: ++ if (!tdi) { ++ printerr(5, "inotify event for unknown wd!!! - " ++ "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", ++ ev->wd, ev->len > 0 ? ev->name : "", ev->mask); ++ rescan = true; ++ } ++ } ++ } ++ ++ if (rescan) ++ gssd_scan(); ++} ++ ++static void + sig_die(int signal) + { +- /* destroy krb5 machine creds */ + if (root_uses_machine_creds) + gssd_destroy_krb5_machine_creds(); + printerr(1, "exiting on signal %d\n", signal); + exit(0); + } + +-void +-sig_hup(int signal) +-{ +- /* don't exit on SIGHUP */ +- printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal); +- return; +-} +- + static void + usage(char *progname) + { +@@ -104,8 +756,9 @@ main(int argc, char *argv[]) + int i; + extern char *optarg; + char *progname; ++ char *ccachedir = NULL; ++ struct event sighup_ev; + +- memset(ccachesearch, 0, sizeof(ccachesearch)); + while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { + switch (opt) { + case 'f': +@@ -127,19 +780,13 @@ main(int argc, char *argv[]) + rpc_verbosity++; + break; + case 'p': +- strncpy(pipefs_dir, optarg, sizeof(pipefs_dir)); +- if (pipefs_dir[sizeof(pipefs_dir)-1] != '\0') +- errx(1, "pipefs path name too long"); ++ pipefs_path = optarg; + break; + case 'k': +- strncpy(keytabfile, optarg, sizeof(keytabfile)); +- if (keytabfile[sizeof(keytabfile)-1] != '\0') +- errx(1, "keytab path name too long"); ++ keytabfile = optarg; + break; + case 'd': +- strncpy(ccachedir, optarg, sizeof(ccachedir)); +- if (ccachedir[sizeof(ccachedir)-1] != '\0') +- errx(1, "ccachedir path name too long"); ++ ccachedir = optarg; + break; + case 't': + context_timeout = atoi(optarg); +@@ -158,7 +805,7 @@ main(int argc, char *argv[]) + #endif + break; + case 'D': +- avoid_dns = 0; ++ avoid_dns = false; + break; + default: + usage(argv[0]); +@@ -174,15 +821,41 @@ main(int argc, char *argv[]) + * the results of getpw*. + */ + if (setenv("HOME", "/", 1)) { +- printerr(1, "Unable to set $HOME: %s\n", strerror(errno)); ++ printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); + exit(1); + } + +- i = 0; +- ccachesearch[i++] = strtok(ccachedir, ":"); +- do { +- ccachesearch[i++] = strtok(NULL, ":"); +- } while (ccachesearch[i-1] != NULL && i < GSSD_MAX_CCACHE_SEARCH); ++ if (ccachedir) { ++ char *ccachedir_copy; ++ char *ptr; ++ ++ for (ptr = ccachedir, i = 2; *ptr; ptr++) ++ if (*ptr == ':') ++ i++; ++ ++ ccachesearch = malloc(i * sizeof(char *)); ++ ccachedir_copy = strdup(ccachedir); ++ if (!ccachedir_copy || !ccachesearch) { ++ printerr(0, "malloc failure\n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ i = 0; ++ ccachesearch[i++] = strtok(ccachedir, ":"); ++ while(ccachesearch[i - 1]) ++ ccachesearch[i++] = strtok(NULL, ":"); ++ ++ } else { ++ ccachesearch = malloc(3 * sizeof(char *)); ++ if (!ccachesearch) { ++ printerr(0, "malloc failure\n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ ccachesearch[0] = GSSD_DEFAULT_CRED_DIR; ++ ccachesearch[1] = GSSD_USER_CRED_DIR; ++ ccachesearch[2] = NULL; ++ } + + if (preferred_realm == NULL) + gssd_k5_get_default_realm(&preferred_realm); +@@ -197,6 +870,13 @@ main(int argc, char *argv[]) + if (verbosity && rpc_verbosity == 0) + rpc_verbosity = verbosity; + authgss_set_debug_level(rpc_verbosity); ++#elif HAVE_LIBTIRPC_SET_DEBUG ++ /* ++ * Only set the libtirpc debug level if explicitly requested via -r... ++ * gssd is chatty enough as it is. ++ */ ++ if (rpc_verbosity > 0) ++ libtirpc_set_debug(progname, rpc_verbosity, fg); + #else + if (rpc_verbosity > 0) + printerr(0, "Warning: rpcsec_gss library does not " +@@ -206,14 +886,42 @@ main(int argc, char *argv[]) + if (gssd_check_mechs() != 0) + errx(1, "Problem with gssapi library"); + +- if (!fg) +- mydaemon(0, 0, pipefds); ++ daemon_init(fg); ++ ++ event_init(); ++ ++ pipefs_dir = opendir(pipefs_path); ++ if (!pipefs_dir) { ++ printerr(0, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ pipefs_fd = dirfd(pipefs_dir); ++ if (fchdir(pipefs_fd)) { ++ printerr(0, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ inotify_fd = inotify_init1(IN_NONBLOCK); ++ if (inotify_fd == -1) { ++ printerr(0, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); ++ exit(EXIT_FAILURE); ++ } + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); +- signal(SIGHUP, sig_hup); ++ signal_set(&sighup_ev, SIGHUP, gssd_scan_cb, NULL); ++ signal_add(&sighup_ev, NULL); ++ event_set(&inotify_ev, inotify_fd, EV_READ | EV_PERSIST, gssd_inotify_cb, NULL); ++ event_add(&inotify_ev, NULL); ++ ++ TAILQ_INIT(&topdir_list); ++ gssd_scan(); ++ daemon_ready(); + +- gssd_run(); +- printerr(0, "gssd_run returned!\n"); +- abort(); ++ event_dispatch(); ++ ++ printerr(0, "ERROR: event_dispatch() returned!\n"); ++ return EXIT_FAILURE; + } ++ +diff -up nfs-utils-1.3.0/utils/gssd/gssd.h.orig nfs-utils-1.3.0/utils/gssd/gssd.h +--- nfs-utils-1.3.0/utils/gssd/gssd.h.orig 2016-04-15 11:42:13.917460638 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.h 2016-04-15 11:42:38.369938424 -0400 +@@ -34,14 +34,12 @@ + #include + #include + #include ++#include ++#include + +-#define MAX_FILE_NAMELEN 32 +-#define FD_ALLOC_BLOCK 256 + #ifndef GSSD_PIPEFS_DIR + #define GSSD_PIPEFS_DIR "/var/lib/nfs/rpc_pipefs" + #endif +-#define INFO "info" +-#define KRB5 "krb5" + #define DNOTIFY_SIGNAL (SIGRTMIN + 3) + + #define GSSD_DEFAULT_CRED_DIR "/tmp" +@@ -50,60 +48,40 @@ + #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" + #define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" + #define GSSD_SERVICE_NAME "nfs" +-#define GSSD_SERVICE_NAME_LEN 3 +-#define GSSD_MAX_CCACHE_SEARCH 16 + + /* + * The gss mechanisms that we can handle + */ + enum {AUTHTYPE_KRB5, AUTHTYPE_LIPKEY}; + +- +- +-extern char pipefs_dir[PATH_MAX]; +-extern char keytabfile[PATH_MAX]; +-extern char *ccachesearch[]; ++extern char *keytabfile; ++extern char **ccachesearch; + extern int use_memcache; + extern int root_uses_machine_creds; + extern unsigned int context_timeout; + extern unsigned int rpc_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; ++ int wd; ++ bool scanned; ++ char *name; ++ char *relpath; + char *servicename; + char *servername; + int prog; + int vers; + char *protocol; + int krb5_fd; +- int krb5_poll_index; +- int krb5_close_me; +- int gssd_fd; +- int gssd_poll_index; +- int gssd_close_me; +- struct sockaddr_storage addr; +-}; +- +-TAILQ_HEAD(topdirs_list_head, topdirs_info) topdirs_list; +- +-struct topdirs_info { +- TAILQ_ENTRY(topdirs_info) list; +- char *dirname; +- int fd; ++ struct event krb5_ev; ++ int gssd_fd; ++ struct event gssd_ev; ++ struct sockaddr_storage addr; + }; + +-void init_client_list(void); +-int update_client_list(void); + void handle_krb5_upcall(struct clnt_info *clp); + void handle_gssd_upcall(struct clnt_info *clp); +-void gssd_run(void); + + + #endif /* _RPC_GSSD_H_ */ +diff -up nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig nfs-utils-1.3.0/utils/gssd/gssd_proc.c +--- nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig 2016-04-15 11:42:13.949461263 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd_proc.c 2016-04-15 11:42:38.371938463 -0400 +@@ -9,6 +9,7 @@ + Copyright (c) 2002 Marius Aamodt Eriksen . + Copyright (c) 2002 Bruce Fields + Copyright (c) 2004 Kevin Coffman ++ Copyright (c) 2014 David H?rdeman + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without +@@ -52,7 +53,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -79,548 +79,6 @@ + #include "nfslib.h" + #include "gss_names.h" + +-/* +- * pollarray: +- * array of struct pollfd suitable to pass to poll. initialized to +- * zero - a zero struct is ignored by poll() because the events mask is 0. +- * +- * clnt_list: +- * linked list of struct clnt_info which associates a clntXXX directory +- * with an index into pollarray[], and other basic data about that client. +- * +- * Directory structure: created by the kernel +- * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel +- * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants +- * a context, write the resulting context +- * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name +- * {rpc_pipefs}/{dir}/clntXX/gssd : pipe for all gss mechanisms using +- * a text-based string of parameters +- * +- * Algorithm: +- * Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files. When data is ready, +- * read and process; performs rpcsec_gss context initialization protocol to +- * get a cred for that user. Writes result to corresponding krb5 file +- * in a form the kernel code will understand. +- * In addition, we make sure we are notified whenever anything is +- * created or destroyed in {rpc_pipefs} or in any of the clntXX directories, +- * and rescan the whole {rpc_pipefs} when this happens. +- */ +- +-struct pollfd * pollarray; +- +-unsigned long pollsize; /* the size of pollaray (in pollfd's) */ +- +-/* Avoid DNS reverse lookups on server names */ +-int avoid_dns = 1; +- +-/* +- * convert a presentation address string to a sockaddr_storage struct. Returns +- * true on success or false on failure. +- * +- * Note that we do not populate the sin6_scope_id field here for IPv6 addrs. +- * gssd nececessarily relies on hostname resolution and DNS AAAA records +- * do not generally contain scope-id's. This means that GSSAPI auth really +- * can't work with IPv6 link-local addresses. +- * +- * We *could* consider changing this if we did something like adopt the +- * Microsoft "standard" of using the ipv6-literal.net domainname, but it's +- * not really feasible at present. +- */ +-static int +-addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port) +-{ +- int rc; +- struct addrinfo *res; +- struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV }; +- +-#ifndef IPV6_SUPPORTED +- hints.ai_family = AF_INET; +-#endif /* IPV6_SUPPORTED */ +- +- rc = getaddrinfo(node, port, &hints, &res); +- if (rc) { +- printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n", +- node, port, rc == EAI_SYSTEM ? strerror(errno) : +- gai_strerror(rc)); +- return 0; +- } +- +-#ifdef IPV6_SUPPORTED +- /* +- * getnameinfo ignores the scopeid. If the address turns out to have +- * a non-zero scopeid, we can't use it -- the resolved host might be +- * completely different from the one intended. +- */ +- if (res->ai_addr->sa_family == AF_INET6) { +- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr; +- if (sin6->sin6_scope_id) { +- printerr(0, "ERROR: address %s has non-zero " +- "sin6_scope_id!\n", node); +- freeaddrinfo(res); +- return 0; +- } +- } +-#endif /* IPV6_SUPPORTED */ +- +- memcpy(sa, res->ai_addr, res->ai_addrlen); +- freeaddrinfo(res); +- return 1; +-} +- +-/* +- * convert a sockaddr to a hostname +- */ +-static char * +-get_servername(const char *name, const struct sockaddr *sa, const char *addr) +-{ +- socklen_t addrlen; +- int err; +- char *hostname; +- char hbuf[NI_MAXHOST]; +- unsigned char buf[sizeof(struct in6_addr)]; +- +- if (avoid_dns) { +- /* +- * Determine if this is a server name, or an IP address. +- * If it is an IP address, do the DNS lookup otherwise +- * skip the DNS lookup. +- */ +- 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) { +- case AF_INET: +- addrlen = sizeof(struct sockaddr_in); +- break; +-#ifdef IPV6_SUPPORTED +- case AF_INET6: +- addrlen = sizeof(struct sockaddr_in6); +- break; +-#endif /* IPV6_SUPPORTED */ +- default: +- printerr(0, "ERROR: unrecognized addr family %d\n", +- sa->sa_family); +- return NULL; +- } +- +- err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0, +- NI_NAMEREQD); +- if (err) { +- printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", +- addr, err == EAI_SYSTEM ? strerror(errno) : +- gai_strerror(err)); +- return NULL; +- } +- +- hostname = strdup(hbuf); +- +- return hostname; +-} +- +-/* XXX buffer problems: */ +-static int +-read_service_info(char *info_file_name, char **servicename, char **servername, +- int *prog, int *vers, char **protocol, +- struct sockaddr *addr) { +-#define INFOBUFLEN 256 +- char buf[INFOBUFLEN + 1]; +- static char server[128]; +- int nbytes; +- static char service[128]; +- static char address[128]; +- char program[16]; +- char version[16]; +- char protoname[16]; +- char port[128]; +- char *p; +- int fd = -1; +- int numfields; +- +- *servicename = *servername = *protocol = NULL; +- +- if ((fd = open(info_file_name, O_RDONLY)) == -1) { +- printerr(0, "ERROR: can't open %s: %s\n", info_file_name, +- strerror(errno)); +- goto fail; +- } +- if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1) +- goto fail; +- close(fd); +- fd = -1; +- buf[nbytes] = '\0'; +- +- numfields = sscanf(buf,"RPC server: %127s\n" +- "service: %127s %15s version %15s\n" +- "address: %127s\n" +- "protocol: %15s\n", +- server, +- service, program, version, +- address, +- protoname); +- +- if (numfields == 5) { +- strcpy(protoname, "tcp"); +- } else if (numfields != 6) { +- goto fail; +- } +- +- port[0] = '\0'; +- if ((p = strstr(buf, "port")) != NULL) +- sscanf(p, "port: %127s\n", port); +- +- /* get program, and version numbers */ +- *prog = atoi(program + 1); /* skip open paren */ +- *vers = atoi(version); +- +- if (!addrstr_to_sockaddr(addr, address, port)) +- goto fail; +- +- *servername = get_servername(server, addr, address); +- if (*servername == NULL) +- goto fail; +- +- nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername); +- if (nbytes > INFOBUFLEN) +- goto fail; +- +- if (!(*servicename = calloc(strlen(buf) + 1, 1))) +- goto fail; +- memcpy(*servicename, buf, strlen(buf)); +- +- if (!(*protocol = strdup(protoname))) +- goto fail; +- return 0; +-fail: +- printerr(0, "ERROR: failed to read service info\n"); +- if (fd != -1) close(fd); +- free(*servername); +- free(*servicename); +- free(*protocol); +- *servicename = *servername = *protocol = NULL; +- return -1; +-} +- +-static void +-destroy_client(struct clnt_info *clp) +-{ +- if (clp->krb5_poll_index != -1) +- memset(&pollarray[clp->krb5_poll_index], 0, +- sizeof(struct pollfd)); +- if (clp->gssd_poll_index != -1) +- memset(&pollarray[clp->gssd_poll_index], 0, +- sizeof(struct pollfd)); +- if (clp->dir_fd != -1) close(clp->dir_fd); +- 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); +- free(clp); +-} +- +-static struct clnt_info * +-insert_new_clnt(void) +-{ +- struct clnt_info *clp = NULL; +- +- if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) { +- printerr(0, "ERROR: can't malloc clnt_info: %s\n", +- strerror(errno)); +- goto out; +- } +- clp->krb5_poll_index = -1; +- clp->gssd_poll_index = -1; +- clp->krb5_fd = -1; +- clp->gssd_fd = -1; +- clp->dir_fd = -1; +- +- TAILQ_INSERT_HEAD(&clnt_list, clp, list); +-out: +- return clp; +-} +- +-static int +-process_clnt_dir_files(struct clnt_info * clp) +-{ +- char name[PATH_MAX]; +- char gname[PATH_MAX]; +- char info_file_name[PATH_MAX]; +- +- if (clp->gssd_close_me) { +- printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname); +- close(clp->gssd_fd); +- memset(&pollarray[clp->gssd_poll_index], 0, +- sizeof(struct pollfd)); +- clp->gssd_fd = -1; +- clp->gssd_poll_index = -1; +- clp->gssd_close_me = 0; +- } +- if (clp->krb5_close_me) { +- printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname); +- close(clp->krb5_fd); +- memset(&pollarray[clp->krb5_poll_index], 0, +- sizeof(struct pollfd)); +- clp->krb5_fd = -1; +- clp->krb5_poll_index = -1; +- clp->krb5_close_me = 0; +- } +- +- if (clp->gssd_fd == -1) { +- snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname); +- clp->gssd_fd = open(gname, O_RDWR); +- } +- if (clp->gssd_fd == -1) { +- if (clp->krb5_fd == -1) { +- snprintf(name, sizeof(name), "%s/krb5", clp->dirname); +- clp->krb5_fd = open(name, O_RDWR); +- } +- +- /* If we opened a gss-specific pipe, let's try opening +- * the new upcall pipe again. If we succeed, close +- * gss-specific pipe(s). +- */ +- if (clp->krb5_fd != -1) { +- clp->gssd_fd = open(gname, O_RDWR); +- if (clp->gssd_fd != -1) { +- if (clp->krb5_fd != -1) +- close(clp->krb5_fd); +- clp->krb5_fd = -1; +- } +- } +- } +- +- if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1)) +- return -1; +- snprintf(info_file_name, sizeof(info_file_name), "%s/info", +- clp->dirname); +- 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; +-} +- +-static int +-get_poll_index(int *ind) +-{ +- unsigned int i; +- +- *ind = -1; +- for (i=0; igssd_fd != -1) && (clp->gssd_poll_index == -1)) { +- if (get_poll_index(&clp->gssd_poll_index)) { +- printerr(0, "ERROR: Too many gssd clients\n"); +- return -1; +- } +- pollarray[clp->gssd_poll_index].fd = clp->gssd_fd; +- pollarray[clp->gssd_poll_index].events |= POLLIN; +- } +- +- if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) { +- if (get_poll_index(&clp->krb5_poll_index)) { +- printerr(0, "ERROR: Too many krb5 clients\n"); +- return -1; +- } +- pollarray[clp->krb5_poll_index].fd = clp->krb5_fd; +- pollarray[clp->krb5_poll_index].events |= POLLIN; +- } +- +- return 0; +-} +- +-static void +-process_clnt_dir(char *dir, char *pdir) +-{ +- struct clnt_info * clp; +- +- 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; +- } +- sprintf(clp->dirname, "%s/%s", pdir, dir); +- if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) { +- 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); +- fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT); +- +- if (process_clnt_dir_files(clp)) +- goto fail_keep_client; +- +- if (insert_clnt_poll(clp)) +- goto fail_destroy_client; +- +- return; +- +-fail_destroy_client: +- if (clp) { +- TAILQ_REMOVE(&clnt_list, clp, list); +- destroy_client(clp); +- } +-fail_keep_client: +- /* We couldn't find some subdirectories, but we keep the client +- * around in case we get a notification on the directory when the +- * subdirectories are created. */ +- return; +-} +- +-void +-init_client_list(void) +-{ +- struct rlimit rlim; +- TAILQ_INIT(&clnt_list); +- /* Eventually plan to grow/shrink poll array: */ +- pollsize = FD_ALLOC_BLOCK; +- if (getrlimit(RLIMIT_NOFILE, &rlim) == 0 && +- rlim.rlim_cur != RLIM_INFINITY) +- pollsize = rlim.rlim_cur; +- pollarray = calloc(pollsize, sizeof(struct pollfd)); +-} +- +-/* +- * This is run after a DNOTIFY signal, and should clear up any +- * directories that are no longer around, and re-scan any existing +- * directories, since the DNOTIFY could have been in there. +- */ +-static void +-update_old_clients(struct dirent **namelist, int size, char *pdir) +-{ +- struct clnt_info *clp; +- void *saveprev; +- int i, stillhere; +- char fname[PATH_MAX]; +- +- for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) { +- /* only compare entries in the global list that are from the +- * same pipefs parent directory as "pdir" +- */ +- if (strcmp(clp->pdir, pdir) != 0) continue; +- +- stillhere = 0; +- for (i=0; i < size; i++) { +- snprintf(fname, sizeof(fname), "%s/%s", +- pdir, namelist[i]->d_name); +- if (strcmp(clp->dirname, fname) == 0) { +- stillhere = 1; +- break; +- } +- } +- if (!stillhere) { +- printerr(2, "destroying client %s\n", clp->dirname); +- saveprev = clp->list.tqe_prev; +- TAILQ_REMOVE(&clnt_list, clp, list); +- destroy_client(clp); +- clp = saveprev; +- } +- } +- for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) { +- if (!process_clnt_dir_files(clp)) +- insert_clnt_poll(clp); +- } +-} +- +-/* Search for a client by directory name, return 1 if found, 0 otherwise */ +-static int +-find_client(char *dirname, char *pdir) +-{ +- struct clnt_info *clp; +- char fname[PATH_MAX]; +- +- for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) { +- snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname); +- if (strcmp(clp->dirname, fname) == 0) +- return 1; +- } +- return 0; +-} +- +-static int +-process_pipedir(char *pipe_name) +-{ +- struct dirent **namelist; +- int i, j; +- +- if (chdir(pipe_name) < 0) { +- printerr(0, "ERROR: can't chdir to %s: %s\n", +- pipe_name, strerror(errno)); +- return -1; +- } +- +- j = scandir(pipe_name, &namelist, NULL, alphasort); +- if (j < 0) { +- printerr(0, "ERROR: can't scandir %s: %s\n", +- pipe_name, strerror(errno)); +- return -1; +- } +- +- update_old_clients(namelist, j, pipe_name); +- for (i=0; i < j; i++) { +- if (!strncmp(namelist[i]->d_name, "clnt", 4) +- && !find_client(namelist[i]->d_name, pipe_name)) +- process_clnt_dir(namelist[i]->d_name, pipe_name); +- free(namelist[i]); +- } +- +- free(namelist); +- +- return 0; +-} +- +-/* Used to read (and re-read) list of clients, set up poll array. */ +-int +-update_client_list(void) +-{ +- int retval = -1; +- struct topdirs_info *tdi; +- +- TAILQ_FOREACH(tdi, &topdirs_list, list) { +- retval = process_pipedir(tdi->dirname); +- if (retval) +- printerr(1, "WARNING: error processing %s\n", +- tdi->dirname); +- +- } +- return retval; +-} +- + /* Encryption types supported by the kernel rpcsec_gss code */ + int num_krb5_enctypes = 0; + krb5_enctype *krb5_enctypes = NULL; +@@ -691,7 +149,7 @@ do_downcall(int k5_fd, uid_t uid, struct + unsigned int timeout = context_timeout; + unsigned int buf_size = 0; + +- printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", ++ printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", + lifetime_rec, acceptor->length, acceptor->value); + buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + + sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + +@@ -730,7 +188,7 @@ do_error_downcall(int k5_fd, uid_t uid, + unsigned int timeout = 0; + int zero = 0; + +- printerr(1, "doing error downcall\n"); ++ printerr(2, "doing error downcall\n"); + + if (WRITE_BYTES(&p, end, uid)) goto out_err; + if (WRITE_BYTES(&p, end, timeout)) goto out_err; +@@ -772,7 +230,7 @@ populate_port(struct sockaddr *sa, const + switch (sa->sa_family) { + case AF_INET: + if (s4->sin_port != 0) { +- printerr(2, "DEBUG: port already set to %d\n", ++ printerr(4, "DEBUG: port already set to %d\n", + ntohs(s4->sin_port)); + return 1; + } +@@ -780,7 +238,7 @@ populate_port(struct sockaddr *sa, const + #ifdef IPV6_SUPPORTED + case AF_INET6: + if (s6->sin6_port != 0) { +- printerr(2, "DEBUG: port already set to %d\n", ++ printerr(4, "DEBUG: port already set to %d\n", + ntohs(s6->sin6_port)); + return 1; + } +@@ -941,7 +399,7 @@ create_auth_rpc_client(struct clnt_info + auth = authgss_create_default(rpc_clnt, tgtname, &sec); + if (!auth) { + /* Our caller should print appropriate message */ +- printerr(2, "WARNING: Failed to create krb5 context for " ++ printerr(1, "WARNING: Failed to create krb5 context for " + "user with uid %d for server %s\n", + uid, tgtname); + goto out_fail; +@@ -1032,7 +490,7 @@ krb5_not_machine_creds(struct clnt_info + char **dname; + int err, resp = -1; + +- printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", ++ printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n", + uid, tgtname); + + *chg_err = change_identity(uid); +@@ -1079,7 +537,7 @@ krb5_use_machine_creds(struct clnt_info + int nocache = 0; + int success = 0; + +- printerr(1, "krb5_use_machine_creds: uid %d tgtname %s\n", ++ printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n", + uid, tgtname); + + do { +@@ -1149,8 +607,6 @@ process_krb5_upcall(struct clnt_info *cl + gss_OID mech; + gss_buffer_desc acceptor = {0}; + +- printerr(1, "handling krb5 upcall (%s)\n", clp->dirname); +- + token.length = 0; + token.value = NULL; + memset(&pd, 0, sizeof(struct authgss_private_data)); +@@ -1176,8 +632,6 @@ process_krb5_upcall(struct clnt_info *cl + * used for this case is not important. + * + */ +- printerr(2, "%s: service is '%s'\n", __func__, +- service ? service : ""); + if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && + service == NULL)) { + +@@ -1191,7 +645,7 @@ process_krb5_upcall(struct clnt_info *cl + /* Child: fall through to rest of function */ + childpid = getpid(); + unsetenv("KRB5CCNAME"); +- printerr(1, "CHILD forked pid %d \n", childpid); ++ printerr(2, "CHILD forked pid %d \n", childpid); + break; + case -1: + /* fork() failed! */ +@@ -1224,9 +678,7 @@ no_fork: + if (auth == NULL) + goto out_return_error; + } else { +- printerr(1, "WARNING: Failed to create krb5 context " +- "for user with uid %d for server %s\n", +- uid, clp->servername); ++ /* krb5_not_machine_creds logs the error */ + goto out_return_error; + } + } +@@ -1257,7 +709,7 @@ no_fork: + * try to use it after this point. + */ + if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { +- printerr(0, "WARNING: Failed to serialize krb5 context for " ++ printerr(1, "WARNING: Failed to serialize krb5 context for " + "user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; +@@ -1300,6 +752,8 @@ handle_krb5_upcall(struct clnt_info *clp + return; + } + ++ printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath); ++ + process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL); + } + +@@ -1311,85 +765,66 @@ handle_gssd_upcall(struct clnt_info *clp + int lbuflen = 0; + char *p; + char *mech = NULL; ++ char *uidstr = NULL; + char *target = NULL; + char *service = NULL; + char *enctypes = NULL; + +- printerr(1, "handling gssd upcall (%s)\n", clp->dirname); +- + if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed reading request\n"); + return; + } +- printerr(2, "%s: '%s'\n", __func__, lbuf); + +- /* find the mechanism name */ +- if ((p = strstr(lbuf, "mech=")) != NULL) { +- mech = malloc(lbuflen); +- if (!mech) +- goto out; +- if (sscanf(p, "mech=%s", mech) != 1) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "failed to parse gss mechanism name " +- "in upcall string '%s'\n", lbuf); +- goto out; +- } +- } else { ++ printerr(2, "\n%s: '%s' (%s)\n", __func__, lbuf, clp->relpath); ++ ++ for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) { ++ if (!strncmp(p, "mech=", strlen("mech="))) ++ mech = p + strlen("mech="); ++ else if (!strncmp(p, "uid=", strlen("uid="))) ++ uidstr = p + strlen("uid="); ++ else if (!strncmp(p, "enctypes=", strlen("enctypes="))) ++ enctypes = p + strlen("enctypes="); ++ else if (!strncmp(p, "target=", strlen("target="))) ++ target = p + strlen("target="); ++ else if (!strncmp(p, "service=", strlen("service="))) ++ service = p + strlen("service="); ++ } ++ ++ if (!mech || strlen(mech) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find gss mechanism name " + "in upcall string '%s'\n", lbuf); +- goto out; ++ return; + } + +- /* read uid */ +- if ((p = strstr(lbuf, "uid=")) != NULL) { +- if (sscanf(p, "uid=%d", &uid) != 1) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "failed to parse uid " +- "in upcall string '%s'\n", lbuf); +- goto out; +- } +- } else { ++ if (uidstr) { ++ uid = (uid_t)strtol(uidstr, &p, 10); ++ if (p == uidstr || *p != '\0') ++ uidstr = NULL; ++ } ++ ++ if (!uidstr) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find uid " + "in upcall string '%s'\n", lbuf); +- goto out; ++ return; + } + +- /* read supported encryption types if supplied */ +- if ((p = strstr(lbuf, "enctypes=")) != NULL) { +- enctypes = malloc(lbuflen); +- if (!enctypes) +- goto out; +- if (sscanf(p, "enctypes=%s", enctypes) != 1) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "failed to parse encryption types " +- "in upcall string '%s'\n", lbuf); +- goto out; +- } +- if (parse_enctypes(enctypes) != 0) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "parsing encryption types failed: errno %d\n", errno); +- } ++ if (enctypes && parse_enctypes(enctypes) != 0) { ++ printerr(0, "WARNING: handle_gssd_upcall: " ++ "parsing encryption types failed: errno %d\n", errno); ++ return; + } + +- /* read target name */ +- if ((p = strstr(lbuf, "target=")) != NULL) { +- target = malloc(lbuflen); +- if (!target) +- goto out; +- if (sscanf(p, "target=%s", target) != 1) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "failed to parse target name " +- "in upcall string '%s'\n", lbuf); +- goto out; +- } ++ if (target && strlen(target) < 1) { ++ printerr(0, "WARNING: handle_gssd_upcall: " ++ "failed to parse target name " ++ "in upcall string '%s'\n", lbuf); ++ return; + } + + /* +- * read the service name +- * + * The presence of attribute "service=" indicates that machine + * credentials should be used for this request. If the value + * is "*", then any machine credentials available can be used. +@@ -1397,16 +832,11 @@ handle_gssd_upcall(struct clnt_info *clp + * the specified service name (always "nfs" for now) should be + * used. + */ +- if ((p = strstr(lbuf, "service=")) != NULL) { +- service = malloc(lbuflen); +- if (!service) +- goto out; +- if (sscanf(p, "service=%s", service) != 1) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "failed to parse service type " +- "in upcall string '%s'\n", lbuf); +- goto out; +- } ++ if (service && strlen(service) < 1) { ++ printerr(0, "WARNING: handle_gssd_upcall: " ++ "failed to parse service type " ++ "in upcall string '%s'\n", lbuf); ++ return; + } + + if (strcmp(mech, "krb5") == 0 && clp->servername) +@@ -1417,13 +847,5 @@ handle_gssd_upcall(struct clnt_info *clp + "received unknown gss mech '%s'\n", mech); + do_error_downcall(clp->gssd_fd, uid, -EACCES); + } +- +-out: +- free(lbuf); +- free(mech); +- free(enctypes); +- free(target); +- free(service); +- return; + } + +diff -up nfs-utils-1.3.0/utils/gssd/gss_util.h.orig nfs-utils-1.3.0/utils/gssd/gss_util.h +--- nfs-utils-1.3.0/utils/gssd/gss_util.h.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gss_util.h 2016-04-15 11:42:38.368938404 -0400 +@@ -52,6 +52,4 @@ int gssd_check_mechs(void); + gss_krb5_set_allowable_enctypes(min, cred, num, types) + #endif + +-extern int avoid_dns; +- + #endif /* _GSS_UTIL_H_ */ +diff -up nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig nfs-utils-1.3.0/utils/gssd/krb5_util.c +--- nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig 2016-04-15 11:42:13.953461341 -0400 ++++ nfs-utils-1.3.0/utils/gssd/krb5_util.c 2016-04-15 11:42:38.372938482 -0400 +@@ -356,7 +356,7 @@ gssd_get_single_krb5_cred(krb5_context c + */ + now += 300; + if (ple->ccname && ple->endtime > now && !nocache) { +- printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", ++ printerr(3, "INFO: Credentials in CC '%s' are good until %d\n", + ple->ccname, ple->endtime); + code = 0; + goto out; +@@ -383,7 +383,7 @@ gssd_get_single_krb5_cred(krb5_context c + "tickets. May have problems behind a NAT.\n"); + #ifdef TEST_SHORT_LIFETIME + /* set a short lifetime (for debugging only!) */ +- printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); ++ printerr(1, "WARNING: Using (debug) short machine cred lifetime!\n"); + krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60); + #endif + opts = init_opts; +@@ -451,8 +451,7 @@ gssd_get_single_krb5_cred(krb5_context c + } + + code = 0; +- printerr(2, "Successfully obtained machine credentials for " +- "principal '%s' stored in ccache '%s'\n", pname, cc_name); ++ printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name); + out: + #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + if (init_opts) +@@ -477,7 +476,7 @@ gssd_set_krb5_ccache_name(char *ccname) + #ifdef USE_GSS_KRB5_CCACHE_NAME + u_int maj_stat, min_stat; + +- printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n", ++ printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", + ccname); + maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL); + if (maj_stat != GSS_S_COMPLETE) { +@@ -492,7 +491,7 @@ gssd_set_krb5_ccache_name(char *ccname) + * function above for which there is no generic gssapi + * equivalent.) + */ +- printerr(2, "using environment variable to select krb5 ccache %s\n", ++ printerr(3, "using environment variable to select krb5 ccache %s\n", + ccname); + setenv("KRB5CCNAME", ccname, 1); + #endif +@@ -1093,8 +1092,8 @@ gssd_setup_krb5_user_gss_ccache(uid_t ui + struct dirent *d; + int err, i, j; + +- printerr(2, "getting credentials for client with uid %u for " +- "server %s\n", uid, servername); ++ printerr(3, "looking for client creds with uid %u for " ++ "server %s in %s\n", uid, servername, dirpattern); + + for (i = 0, j = 0; dirpattern[i] != '\0'; i++) { + switch (dirpattern[i]) { +@@ -1410,16 +1409,21 @@ gssd_acquire_krb5_cred(gss_cred_id_t *gs + int + gssd_acquire_user_cred(gss_cred_id_t *gss_cred) + { +- OM_uint32 min_stat; ++ OM_uint32 maj_stat, min_stat; + int ret; + + ret = gssd_acquire_krb5_cred(gss_cred); + + /* force validation of cred to check for expiry */ + if (ret == 0) { +- if (gss_inquire_cred(&min_stat, *gss_cred, NULL, NULL, +- NULL, NULL) != GSS_S_COMPLETE) +- ret = -1; ++ maj_stat = gss_inquire_cred(&min_stat, *gss_cred, ++ NULL, NULL, NULL, NULL); ++ if (maj_stat != GSS_S_COMPLETE) { ++ if (get_verbosity() > 0) ++ pgsserr("gss_inquire_cred", ++ maj_stat, min_stat, &krb5oid); ++ ret = -1; ++ } + } + + return ret; +diff -up nfs-utils-1.3.0/utils/gssd/Makefile.am.orig nfs-utils-1.3.0/utils/gssd/Makefile.am +--- nfs-utils-1.3.0/utils/gssd/Makefile.am.orig 2016-04-15 11:42:13.942461126 -0400 ++++ nfs-utils-1.3.0/utils/gssd/Makefile.am 2016-04-15 11:42:38.367938385 -0400 +@@ -29,7 +29,6 @@ COMMON_SRCS = \ + gssd_SOURCES = \ + $(COMMON_SRCS) \ + gssd.c \ +- gssd_main_loop.c \ + gssd_proc.c \ + krb5_util.c \ + \ +@@ -37,12 +36,23 @@ gssd_SOURCES = \ + krb5_util.h \ + write_bytes.h + +-gssd_LDADD = ../../support/nfs/libnfs.a \ +- $(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS) +-gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC) ++gssd_LDADD = \ ++ ../../support/nfs/libnfs.a \ ++ $(LIBEVENT) \ ++ $(RPCSECGSS_LIBS) \ ++ $(KRBLIBS) \ ++ $(GSSAPI_LIBS) \ ++ $(LIBTIRPC) + +-gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ +- $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS) ++gssd_LDFLAGS = \ ++ $(KRBLDFLAGS) ++ ++gssd_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(CFLAGS) \ ++ $(RPCSECGSS_CFLAGS) \ ++ $(KRBCFLAGS) \ ++ $(GSSAPI_CFLAGS) + + svcgssd_SOURCES = \ + $(COMMON_SRCS) \ +diff -up nfs-utils-1.3.0/utils/gssd/svcgssd.c.orig nfs-utils-1.3.0/utils/gssd/svcgssd.c +--- nfs-utils-1.3.0/utils/gssd/svcgssd.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/gssd/svcgssd.c 2016-04-15 11:42:38.372938482 -0400 +@@ -62,8 +62,6 @@ + #include "gss_util.h" + #include "err_util.h" + +-static int pipefds[2] = { -1, -1 }; +- + void + sig_die(int signal) + { +@@ -137,6 +135,13 @@ main(int argc, char *argv[]) + if (verbosity && rpc_verbosity == 0) + rpc_verbosity = verbosity; + authgss_set_debug_level(rpc_verbosity); ++#elif HAVE_LIBTIRPC_SET_DEBUG ++ /* ++ * Only set the libtirpc debug level if explicitly requested via -r... ++ * svcgssd is chatty enough as it is. ++ */ ++ if (rpc_verbosity > 0) ++ libtirpc_set_debug(progname, rpc_verbosity, fg); + #else + if (rpc_verbosity > 0) + printerr(0, "Warning: rpcsec_gss library does not " +@@ -157,8 +162,7 @@ main(int argc, char *argv[]) + exit(1); + } + +- if (!fg) +- mydaemon(0, 0, pipefds); ++ daemon_init(fg); + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); +@@ -187,8 +191,7 @@ main(int argc, char *argv[]) + } + } + +- if (!fg) +- release_parent(pipefds); ++ daemon_ready(); + + nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ + gssd_run(); +diff -up nfs-utils-1.3.0/utils/idmapd/idmapd.c.orig nfs-utils-1.3.0/utils/idmapd/idmapd.c +--- nfs-utils-1.3.0/utils/idmapd/idmapd.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/idmapd/idmapd.c 2016-04-15 11:42:38.373938502 -0400 +@@ -164,7 +164,6 @@ 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; +@@ -302,8 +301,7 @@ main(int argc, char **argv) + if (nfs4_init_name_mapping(conf_path)) + errx(1, "Unable to create name to user id mappings."); + +- if (!fg) +- mydaemon(0, 0, pipefds); ++ daemon_init(fg); + + event_init(); + +@@ -380,7 +378,7 @@ main(int argc, char **argv) + if (nfsdret != 0 && fd == 0) + xlog_err("main: Neither NFS client nor NFSd found"); + +- release_parent(pipefds); ++ daemon_ready(); + + if (event_dispatch() < 0) + xlog_err("main: event_dispatch returns errno %d (%s)", +diff -up nfs-utils-1.3.0/utils/statd/statd.c.orig nfs-utils-1.3.0/utils/statd/statd.c +--- nfs-utils-1.3.0/utils/statd/statd.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/utils/statd/statd.c 2016-04-15 11:42:38.373938502 -0400 +@@ -248,13 +248,12 @@ int main (int argc, char **argv) + int nlm_udp = 0, nlm_tcp = 0; + struct rlimit rlim; + +- int pipefds[2] = { -1, -1}; +- char status; +- + /* Default: daemon mode, no other options */ + run_mode = 0; +- xlog_stderr(0); +- xlog_syslog(1); ++ ++ /* Log to stderr if there's an error during startup */ ++ xlog_stderr(1); ++ xlog_syslog(0); + + /* Set the basename */ + if ((name_p = strrchr(argv[0],'/')) != NULL) { +@@ -394,52 +393,17 @@ int main (int argc, char **argv) + simulator (--argc, ++argv); /* simulator() does exit() */ + #endif + +- if (!(run_mode & MODE_NODAEMON)) { +- int tempfd; +- +- if (pipe(pipefds)<0) { +- perror("statd: unable to create pipe"); +- exit(1); +- } +- if ((pid = fork ()) < 0) { +- perror ("statd: Could not fork"); +- exit (1); +- } else 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 (); +- +- while (pipefds[1] <= 2) { +- pipefds[1] = dup(pipefds[1]); +- if (pipefds[1]<0) { +- perror("statd: dup"); +- exit(1); +- } +- } +- tempfd = open("/dev/null", O_RDWR); +- dup2(tempfd, 0); +- dup2(tempfd, 1); +- dup2(tempfd, 2); +- dup2(pipefds[1], 3); +- pipefds[1] = 3; +- closeall(4); +- } +- +- /* Child. */ ++ daemon_init((run_mode & MODE_NODAEMON)); + + if (run_mode & MODE_LOG_STDERR) { + xlog_syslog(0); + xlog_stderr(1); + xlog_config(D_ALL, 1); ++ } else { ++ xlog_syslog(1); ++ xlog_stderr(0); + } ++ + xlog_open(name_p); + xlog(L_NOTICE, "Version " VERSION " starting"); + +@@ -512,16 +476,8 @@ int main (int argc, char **argv) + } + atexit(statd_unregister); + +- /* If we got this far, we have successfully started, so notify parent */ +- if (pipefds[1] > 0) { +- status = 0; +- if (write(pipefds[1], &status, 1) != 1) { +- xlog_warn("writing to parent pipe failed: errno %d (%s)\n", +- errno, strerror(errno)); +- } +- close(pipefds[1]); +- pipefds[1] = -1; +- } ++ /* If we got this far, we have successfully started */ ++ daemon_ready(); + + for (;;) { + /* diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-errno-typo.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-errno-typo.patch new file mode 100644 index 0000000..a5e6a5f --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-errno-typo.patch @@ -0,0 +1,21 @@ +commit 404c79c81df0548d50216cddc7d2c4ebfca45c45 +Author: Steve Dickson +Date: Fri Jul 25 10:48:16 2014 -0400 + + gssd: Fixed errno typo in get_servername() + + Signed-off-by: Steve Dickson + +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index 40ff188..9925dab 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -218,7 +218,7 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) + NI_NAMEREQD); + if (err) { + printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", +- addr, err == EAI_SYSTEM ? strerror(err) : ++ addr, err == EAI_SYSTEM ? strerror(errno) : + gai_strerror(err)); + return NULL; + } diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-findkeytab.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-findkeytab.patch new file mode 100644 index 0000000..ab1ce68 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-findkeytab.patch @@ -0,0 +1,23 @@ +diff -up nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig nfs-utils-1.3.0/utils/gssd/krb5_util.c +--- nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig 2016-05-16 08:46:45.554915290 -0400 ++++ nfs-utils-1.3.0/utils/gssd/krb5_util.c 2016-05-16 09:13:09.479879099 -0400 +@@ -768,7 +768,7 @@ find_keytab_entry(krb5_context context, + char **realmnames = NULL; + char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; + char myhostad[NI_MAXHOST+1]; +- int i, j, retval; ++ int i, j, k, retval; + char *default_realm = NULL; + char *realm; + char *k5err = NULL; +@@ -913,8 +913,8 @@ find_keytab_entry(krb5_context context, + * moving on to the svcname + */ + if (strcmp(svcnames[j],"$") == 0 && !tried_upper) { +- for (i = 0; myhostad[i] != '$'; ++i) { +- myhostad[i] = toupper(myhostad[i]); ++ for (k = 0; myhostad[k] != '$'; ++k) { ++ myhostad[k] = toupper(myhostad[k]); + } + j--; + tried_upper = 1; diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-maccout-nocase.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-maccout-nocase.patch new file mode 100644 index 0000000..92e2d7d --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-maccout-nocase.patch @@ -0,0 +1,66 @@ +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index 5fde091..990111d 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -801,8 +801,10 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, + char *default_realm = NULL; + char *realm; + char *k5err = NULL; +- int tried_all = 0, tried_default = 0; ++ int tried_all = 0, tried_default = 0, tried_upper = 0; + krb5_principal princ; ++ const char *notsetstr = "not set"; ++ char *adhostoverride; + + + /* Get full target hostname */ +@@ -820,13 +822,23 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, + } + + /* Compute the active directory machine name HOST$ */ +- strcpy(myhostad, myhostname); +- for (i = 0; myhostad[i] != 0; ++i) { +- if (myhostad[i] == '.') break; +- myhostad[i] = toupper(myhostad[i]); ++ krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", ++ notsetstr, &adhostoverride); ++ if (strcmp(adhostoverride, notsetstr) != 0) { ++ printerr (1, ++ "AD host string overridden with \"%s\" from appdefaults\n", ++ adhostoverride); ++ /* No overflow: Windows cannot handle strings longer than 19 chars */ ++ strcpy(myhostad, adhostoverride); ++ free(adhostoverride); ++ } else { ++ strcpy(myhostad, myhostname); ++ for (i = 0; myhostad[i] != 0; ++i) { ++ if (myhostad[i] == '.') break; ++ } ++ myhostad[i] = '$'; ++ myhostad[i+1] = 0; + } +- myhostad[i] = '$'; +- myhostad[i+1] = 0; + + retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); + if (retval) { +@@ -923,6 +935,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, + k5err = gssd_k5_err_msg(context, code); + printerr(3, "%s while getting keytab entry for '%s'\n", + k5err, spn); ++ /* ++ * We tried the active directory machine account ++ * with the hostname part as-is and failed... ++ * convert it to uppercase and try again before ++ * moving on to the svcname ++ */ ++ if (strcmp(svcnames[j],"$") == 0 && !tried_upper) { ++ for (i = 0; myhostad[i] != '$'; ++i) { ++ myhostad[i] = toupper(myhostad[i]); ++ } ++ j--; ++ tried_upper = 1; ++ } + } else { + printerr(3, "Success getting keytab entry for '%s'\n",spn); + retval = 0; diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-multithread.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-multithread.patch new file mode 100644 index 0000000..6d333b4 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-multithread.patch @@ -0,0 +1,594 @@ +diff --git a/aclocal/kerberos5.m4 b/aclocal/kerberos5.m4 +index 0bf35d3..8a0f3e4 100644 +--- a/aclocal/kerberos5.m4 ++++ b/aclocal/kerberos5.m4 +@@ -43,15 +43,6 @@ AC_DEFUN([AC_KERBEROS_V5],[ + -f $dir/lib/libgssapi_krb5.so \) ; then + AC_DEFINE(HAVE_KRB5, 1, [Define this if you have MIT Kerberos libraries]) + KRBDIR="$dir" +- dnl If we are using MIT K5 1.3.1 and before, we *MUST* use the +- dnl private function (gss_krb5_ccache_name) to get correct +- dnl behavior of changing the ccache used by gssapi. +- dnl Starting in 1.3.2, we *DO NOT* want to use +- dnl gss_krb5_ccache_name, instead we want to set KRB5CCNAME +- dnl to get gssapi to use a different ccache +- if test $K5VERS -le 131; then +- AC_DEFINE(USE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the private function, gss_krb5_cache_name, must be used to tell the Kerberos library which credentials cache to use. Otherwise, this is done by setting the KRB5CCNAME environment variable]) +- fi + gssapi_lib=gssapi_krb5 + break + dnl The following ugly hack brought on by the split installation +@@ -92,8 +83,6 @@ AC_DEFUN([AC_KERBEROS_V5],[ + AC_DEFINE(HAVE_LUCID_CONTEXT_SUPPORT, 1, [Define this if the Kerberos GSS library supports gss_krb5_export_lucid_sec_context]), ,$KRBLIBS) + AC_CHECK_LIB($gssapi_lib, gss_krb5_set_allowable_enctypes, + AC_DEFINE(HAVE_SET_ALLOWABLE_ENCTYPES, 1, [Define this if the Kerberos GSS library supports gss_krb5_set_allowable_enctypes]), ,$KRBLIBS) +- AC_CHECK_LIB($gssapi_lib, gss_krb5_ccache_name, +- AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the Kerberos GSS library supports gss_krb5_ccache_name]), ,$KRBLIBS) + AC_CHECK_LIB($gssapi_lib, gss_krb5_free_lucid_sec_context, + AC_DEFINE(HAVE_GSS_KRB5_FREE_LUCID_SEC_CONTEXT, 1, [Define this if the Kerberos GSS library supports gss_krb5_free_lucid_sec_context]), ,$KRBLIBS) + +diff --git a/aclocal/libpthread.m4 b/aclocal/libpthread.m4 +new file mode 100644 +index 0000000..e87d2a0 +--- /dev/null ++++ b/aclocal/libpthread.m4 +@@ -0,0 +1,13 @@ ++dnl Checks for pthreads library and headers ++dnl ++AC_DEFUN([AC_LIBPTHREAD], [ ++ ++ dnl Check for library, but do not add -lpthreads to LIBS ++ AC_CHECK_LIB([pthread], [pthread_create], [LIBPTHREAD=-lpthread], ++ [AC_MSG_ERROR([libpthread not found.])]) ++ AC_SUBST(LIBPTHREAD) ++ ++ AC_CHECK_HEADERS([pthread.h], , ++ [AC_MSG_ERROR([libpthread headers not found.])]) ++ ++])dnl +diff --git a/configure.ac b/configure.ac +index 4ee4db5..56f7f3e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -355,6 +355,9 @@ if test "$enable_gss" = yes; then + dnl Invoked after AC_KERBEROS_V5; AC_LIBRPCSECGSS needs to have KRBLIBS set + AC_LIBRPCSECGSS + ++ dnl Check for pthreads ++ AC_LIBPTHREAD ++ + dnl librpcsecgss already has a dependency on libgssapi, + dnl but we need to make sure we get the right version + if test "$enable_gss" = yes; then +diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am +index fd488a1..f387c16 100644 +--- a/utils/gssd/Makefile.am ++++ b/utils/gssd/Makefile.am +@@ -42,7 +42,8 @@ gssd_LDADD = \ + $(RPCSECGSS_LIBS) \ + $(KRBLIBS) \ + $(GSSAPI_LIBS) \ +- $(LIBTIRPC) ++ $(LIBTIRPC) \ ++ $(LIBPTHREAD) + + gssd_LDFLAGS = \ + $(KRBLDFLAGS) +diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c +index 7ba27b1..43fccaf 100644 +--- a/utils/gssd/gssd.c ++++ b/utils/gssd/gssd.c +@@ -87,7 +87,9 @@ unsigned int rpc_timeout = 5; + char *preferred_realm = NULL; + /* Avoid DNS reverse lookups on server names */ + static bool avoid_dns = true; +- ++int thread_started = false; ++pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER; ++pthread_cond_t pcond = PTHREAD_COND_INITIALIZER; + + TAILQ_HEAD(topdir_list_head, topdir) topdir_list; + +@@ -361,20 +363,91 @@ gssd_destroy_client(struct clnt_info *clp) + + static void gssd_scan(void); + ++static int ++start_upcall_thread(void (*func)(struct clnt_upcall_info *), void *info) ++{ ++ pthread_attr_t attr; ++ pthread_t th; ++ int ret; ++ ++ ret = pthread_attr_init(&attr); ++ if (ret != 0) { ++ printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n", ++ ret, strerror(errno)); ++ return ret; ++ } ++ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ if (ret != 0) { ++ printerr(0, "ERROR: failed to create pthread attr: ret %d: " ++ "%s\n", ret, strerror(errno)); ++ return ret; ++ } ++ ++ ret = pthread_create(&th, &attr, (void *)func, (void *)info); ++ if (ret != 0) ++ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n", ++ ret, strerror(errno)); ++ return ret; ++} ++ ++static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp) ++{ ++ struct clnt_upcall_info *info; ++ ++ info = malloc(sizeof(struct clnt_upcall_info)); ++ if (info == NULL) ++ return NULL; ++ info->clp = clp; ++ ++ return info; ++} ++ ++/* For each upcall read the upcall info into the buffer, then create a ++ * thread in a detached state so that resources are released back into ++ * the system without the need for a join. ++ */ + static void + gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) + { + struct clnt_info *clp = data; ++ struct clnt_upcall_info *info; ++ ++ info = alloc_upcall_info(clp); ++ if (info == NULL) ++ return; ++ ++ info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf)); ++ if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') { ++ printerr(0, "WARNING: %s: failed reading request\n", __func__); ++ free(info); ++ return; ++ } ++ info->lbuf[info->lbuflen-1] = 0; + +- handle_gssd_upcall(clp); ++ if (start_upcall_thread(handle_gssd_upcall, info)) ++ free(info); + } + + static void + gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) + { + struct clnt_info *clp = data; ++ struct clnt_upcall_info *info; ++ ++ info = alloc_upcall_info(clp); ++ if (info == NULL) ++ return; ++ ++ if (read(clp->krb5_fd, &info->uid, ++ sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) { ++ printerr(0, "WARNING: %s: failed reading uid from krb5 " ++ "upcall pipe: %s\n", __func__, strerror(errno)); ++ free(info); ++ return; ++ } + +- handle_krb5_upcall(clp); ++ if (start_upcall_thread(handle_krb5_upcall, info)) ++ free(info); + } + + static struct clnt_info * +diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h +index c6937c5..f4f5975 100644 +--- a/utils/gssd/gssd.h ++++ b/utils/gssd/gssd.h +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #ifndef GSSD_PIPEFS_DIR + #define GSSD_PIPEFS_DIR "/var/lib/nfs/rpc_pipefs" +@@ -48,7 +49,7 @@ + #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" + #define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" + #define GSSD_SERVICE_NAME "nfs" +- ++#define RPC_CHAN_BUF_SIZE 32768 + /* + * The gss mechanisms that we can handle + */ +@@ -61,6 +62,10 @@ extern int root_uses_machine_creds; + extern unsigned int context_timeout; + extern unsigned int rpc_timeout; + extern char *preferred_realm; ++extern pthread_mutex_t ple_lock; ++extern pthread_cond_t pcond; ++extern pthread_mutex_t pmutex; ++extern int thread_started; + + struct clnt_info { + TAILQ_ENTRY(clnt_info) list; +@@ -80,8 +85,15 @@ struct clnt_info { + struct sockaddr_storage addr; + }; + +-void handle_krb5_upcall(struct clnt_info *clp); +-void handle_gssd_upcall(struct clnt_info *clp); ++struct clnt_upcall_info { ++ struct clnt_info *clp; ++ char lbuf[RPC_CHAN_BUF_SIZE]; ++ int lbuflen; ++ uid_t uid; ++}; ++ ++void handle_krb5_upcall(struct clnt_upcall_info *clp); ++void handle_gssd_upcall(struct clnt_upcall_info *clp); + + + #endif /* _RPC_GSSD_H_ */ +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index 69c6a34..fda7595 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -69,6 +69,7 @@ + #include + #include + #include ++#include + + #include "gssd.h" + #include "err_util.h" +@@ -442,7 +443,7 @@ change_identity(uid_t uid) + struct passwd *pw; + + /* drop list of supplimentary groups first */ +- if (setgroups(0, NULL) != 0) { ++ if (syscall(SYS_setgroups, 0, 0) != 0) { + printerr(0, "WARNING: unable to drop supplimentary groups!"); + return errno; + } +@@ -459,20 +460,18 @@ change_identity(uid_t uid) + } + } + +- /* +- * Switch the GIDs. Note that we leave the saved-set-gid alone in an +- * attempt to prevent attacks via ptrace() ++ /* Switch the UIDs and GIDs. */ ++ /* For the threaded version we have to set uid,gid per thread instead ++ * of per process. glibc setresuid() when called from a thread, it'll ++ * send a signal to all other threads to synchronize the uid in all ++ * other threads. To bypass this, we have to call syscall() directly. + */ +- if (setresgid(pw->pw_gid, pw->pw_gid, -1) != 0) { ++ if (syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { + printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid); + return errno; + } + +- /* +- * Switch UIDs, but leave saved-set-uid alone to prevent ptrace() by +- * other processes running with this uid. +- */ +- if (setresuid(uid, uid, -1) != 0) { ++ if (syscall(SYS_setresuid, uid, uid, uid) != 0) { + printerr(0, "WARNING: Failed to setuid for user with uid %u\n", + uid); + return errno; +@@ -554,7 +553,15 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, + goto out; + } + for (ccname = credlist; ccname && *ccname; ccname++) { +- gssd_setup_krb5_machine_gss_ccache(*ccname); ++ u_int min_stat; ++ ++ if (gss_krb5_ccache_name(&min_stat, *ccname, NULL) != ++ GSS_S_COMPLETE) { ++ printerr(1, "WARNING: gss_krb5_ccache_name " ++ "with name '%s' failed (%s)\n", ++ *ccname, error_message(min_stat)); ++ continue; ++ } + if ((create_auth_rpc_client(clp, tgtname, rpc_clnt, + &auth, uid, + AUTHTYPE_KRB5, +@@ -602,7 +609,6 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + gss_buffer_desc token; + int err, downcall_err = -EACCES; + OM_uint32 maj_stat, min_stat, lifetime_rec; +- pid_t pid, childpid = -1; + gss_name_t gacceptor = GSS_C_NO_NAME; + gss_OID mech; + gss_buffer_desc acceptor = {0}; +@@ -635,36 +641,6 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && + service == NULL)) { + +- /* already running as uid 0 */ +- if (uid == 0) +- goto no_fork; +- +- pid = fork(); +- switch(pid) { +- case 0: +- /* Child: fall through to rest of function */ +- childpid = getpid(); +- unsetenv("KRB5CCNAME"); +- printerr(2, "CHILD forked pid %d \n", childpid); +- break; +- case -1: +- /* fork() failed! */ +- printerr(0, "WARNING: unable to fork() to handle" +- "upcall: %s\n", strerror(errno)); +- return; +- default: +- /* Parent: just wait on child to exit and return */ +- do { +- pid = wait(&err); +- } while(pid == -1 && errno != -ECHILD); +- +- if (WIFSIGNALED(err)) +- printerr(0, "WARNING: forked child was killed" +- "with signal %d\n", WTERMSIG(err)); +- return; +- } +-no_fork: +- + auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err, + &err, &rpc_clnt); + if (err) +@@ -730,11 +706,7 @@ out: + if (rpc_clnt) + clnt_destroy(rpc_clnt); + +- pid = getpid(); +- if (pid == childpid) +- exit(0); +- else +- return; ++ return; + + out_return_error: + do_error_downcall(fd, uid, downcall_err); +@@ -742,27 +714,21 @@ out_return_error: + } + + void +-handle_krb5_upcall(struct clnt_info *clp) ++handle_krb5_upcall(struct clnt_upcall_info *info) + { +- uid_t uid; +- +- if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { +- printerr(0, "WARNING: failed reading uid from krb5 " +- "upcall pipe: %s\n", strerror(errno)); +- return; +- } ++ struct clnt_info *clp = info->clp; + +- printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath); ++ printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); + +- process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL); ++ process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL); ++ free(info); + } + + void +-handle_gssd_upcall(struct clnt_info *clp) ++handle_gssd_upcall(struct clnt_upcall_info *info) + { ++ struct clnt_info *clp = info->clp; + uid_t uid; +- char *lbuf = NULL; +- int lbuflen = 0; + char *p; + char *mech = NULL; + char *uidstr = NULL; +@@ -770,15 +736,9 @@ handle_gssd_upcall(struct clnt_info *clp) + char *service = NULL; + char *enctypes = NULL; + +- if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) { +- printerr(0, "WARNING: handle_gssd_upcall: " +- "failed reading request\n"); +- return; +- } +- +- printerr(2, "\n%s: '%s' (%s)\n", __func__, lbuf, clp->relpath); ++ printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); + +- for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) { ++ for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) { + if (!strncmp(p, "mech=", strlen("mech="))) + mech = p + strlen("mech="); + else if (!strncmp(p, "uid=", strlen("uid="))) +@@ -794,8 +754,8 @@ handle_gssd_upcall(struct clnt_info *clp) + if (!mech || strlen(mech) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find gss mechanism name " +- "in upcall string '%s'\n", lbuf); +- return; ++ "in upcall string '%s'\n", info->lbuf); ++ goto out; + } + + if (uidstr) { +@@ -807,21 +767,21 @@ handle_gssd_upcall(struct clnt_info *clp) + if (!uidstr) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find uid " +- "in upcall string '%s'\n", lbuf); +- return; ++ "in upcall string '%s'\n", info->lbuf); ++ goto out; + } + + if (enctypes && parse_enctypes(enctypes) != 0) { + printerr(0, "WARNING: handle_gssd_upcall: " + "parsing encryption types failed: errno %d\n", errno); +- return; ++ goto out; + } + + if (target && strlen(target) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse target name " +- "in upcall string '%s'\n", lbuf); +- return; ++ "in upcall string '%s'\n", info->lbuf); ++ goto out; + } + + /* +@@ -835,8 +795,8 @@ handle_gssd_upcall(struct clnt_info *clp) + if (service && strlen(service) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse service type " +- "in upcall string '%s'\n", lbuf); +- return; ++ "in upcall string '%s'\n", info->lbuf); ++ goto out; + } + + if (strcmp(mech, "krb5") == 0 && clp->servername) +@@ -847,5 +807,8 @@ handle_gssd_upcall(struct clnt_info *clp) + "received unknown gss mech '%s'\n", mech); + do_error_downcall(clp->gssd_fd, uid, -EACCES); + } ++out: ++ free(info); ++ return; + } + +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index 3849b6a..bc29787 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -128,6 +128,7 @@ + + /* Global list of principals/cache file names for machine credentials */ + struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; ++pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER; + + #ifdef HAVE_SET_ALLOWABLE_ENCTYPES + int limit_to_legacy_enctypes = 0; +@@ -467,37 +468,6 @@ gssd_get_single_krb5_cred(krb5_context context, + } + + /* +- * Depending on the version of Kerberos, we either need to use +- * a private function, or simply set the environment variable. +- */ +-static void +-gssd_set_krb5_ccache_name(char *ccname) +-{ +-#ifdef USE_GSS_KRB5_CCACHE_NAME +- u_int maj_stat, min_stat; +- +- printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", +- ccname); +- maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL); +- if (maj_stat != GSS_S_COMPLETE) { +- printerr(0, "WARNING: gss_krb5_ccache_name with " +- "name '%s' failed (%s)\n", +- ccname, error_message(min_stat)); +- } +-#else +- /* +- * Set the KRB5CCNAME environment variable to tell the krb5 code +- * which credentials cache to use. (Instead of using the private +- * function above for which there is no generic gssapi +- * equivalent.) +- */ +- printerr(3, "using environment variable to select krb5 ccache %s\n", +- ccname); +- setenv("KRB5CCNAME", ccname, 1); +-#endif +-} +- +-/* + * Given a principal, find a matching ple structure + */ + static struct gssd_k5_kt_princ * +@@ -586,10 +556,12 @@ get_ple_by_princ(krb5_context context, krb5_principal princ) + + /* Need to serialize list if we ever become multi-threaded! */ + ++ pthread_mutex_lock(&ple_lock); + ple = find_ple_by_princ(context, princ); + if (ple == NULL) { + ple = new_ple(context, princ); + } ++ pthread_mutex_unlock(&ple_lock); + + return ple; + } +@@ -1091,6 +1063,7 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) + const char *cctype; + struct dirent *d; + int err, i, j; ++ u_int maj_stat, min_stat; + + printerr(3, "looking for client creds with uid %u for " + "server %s in %s\n", uid, servername, dirpattern); +@@ -1126,22 +1099,16 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) + + printerr(2, "using %s as credentials cache for client with " + "uid %u for server %s\n", buf, uid, servername); +- gssd_set_krb5_ccache_name(buf); +- return 0; +-} + +-/* +- * Let the gss code know where to find the machine credentials ccache. +- * +- * Returns: +- * void +- */ +-void +-gssd_setup_krb5_machine_gss_ccache(char *ccname) +-{ +- printerr(2, "using %s as credentials cache for machine creds\n", +- ccname); +- gssd_set_krb5_ccache_name(ccname); ++ printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", ++ buf); ++ maj_stat = gss_krb5_ccache_name(&min_stat, buf, NULL); ++ if (maj_stat != GSS_S_COMPLETE) { ++ printerr(0, "ERROR: unable to get user cred cache '%s' " ++ "failed (%s)\n", buf, error_message(min_stat)); ++ return maj_stat; ++ } ++ return 0; + } + + /* +diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h +index a319588..e3bbb07 100644 +--- a/utils/gssd/krb5_util.h ++++ b/utils/gssd/krb5_util.h +@@ -27,7 +27,6 @@ int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, + char *dirname); + int gssd_get_krb5_machine_cred_list(char ***list); + void gssd_free_krb5_machine_cred_list(char **list); +-void gssd_setup_krb5_machine_gss_ccache(char *servername); + void gssd_destroy_krb5_machine_creds(void); + int gssd_refresh_krb5_machine_credential(char *hostname, + struct gssd_k5_kt_princ *ple, +@@ -55,8 +54,6 @@ int limit_krb5_enctypes(struct rpc_gss_sec *sec); + #define k5_free_unparsed_name(ctx, name) free(name) + #define k5_free_default_realm(ctx, realm) free(realm) + #define k5_free_kt_entry(ctx, kte) krb5_kt_free_entry((ctx),(kte)) +-#undef USE_GSS_KRB5_CCACHE_NAME +-#define USE_GSS_KRB5_CCACHE_NAME 1 + #endif + + #endif /* KRB5_UTIL_H */ diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-noerror-message.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-noerror-message.patch new file mode 100644 index 0000000..54978b1 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-noerror-message.patch @@ -0,0 +1,44 @@ +commit fe91df5e1d115015b31bb055ef0b4d5dfdc0635c +Author: Steve Dickson +Date: Tue Jul 8 10:29:52 2014 -0400 + + gssd: Error out when rpc_pipefs directory is empty + + When there is no kernel modules loaded the rpc_pipefs + directory is empty, which cause rpc.gssd to silently + exit. + + This patch adds a check to see if the topdirs_list + is empty. If so error out without dropping a core. + + Signed-off-by: Steve Dickson + +diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c +index 9970028..6946ab6 100644 +--- a/utils/gssd/gssd_main_loop.c ++++ b/utils/gssd/gssd_main_loop.c +@@ -173,6 +173,10 @@ topdirs_init_list(void) + if (ret) + goto out_err; + } ++ if (TAILQ_EMPTY(&topdirs_list)) { ++ printerr(0, "ERROR: rpc_pipefs directory '%s' is empty!\n", pipefs_dir); ++ return -1; ++ } + closedir(pipedir); + return 0; + out_err: +@@ -233,9 +237,10 @@ gssd_run() + sigaddset(&set, DNOTIFY_SIGNAL); + sigprocmask(SIG_UNBLOCK, &set, NULL); + +- if (topdirs_init_list() != 0) +- return; +- ++ if (topdirs_init_list() != 0) { ++ /* Error msg is already printed */ ++ exit(1); ++ } + init_client_list(); + + printerr(1, "beginning poll\n"); diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-preferred-realm.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-preferred-realm.patch new file mode 100644 index 0000000..f8574f2 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-preferred-realm.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig nfs-utils-1.3.0/utils/gssd/krb5_util.c +--- nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig 2017-03-31 16:34:11.775037704 -0400 ++++ nfs-utils-1.3.0/utils/gssd/krb5_util.c 2017-04-08 15:18:53.619038636 -0400 +@@ -848,7 +848,7 @@ find_keytab_entry(krb5_context context, + i = 0; + realm = realmnames[i]; + +- if (strcmp (realm, preferred_realm) != 0) { ++ if (preferred_realm && strcmp (realm, preferred_realm) != 0) { + realm = preferred_realm; + /* resetting the realmnames index */ + i = -1; diff --git a/SOURCES/nfs-utils-1.3.0-rpcgssd-timeout.patch b/SOURCES/nfs-utils-1.3.0-rpcgssd-timeout.patch new file mode 100644 index 0000000..dba38e9 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcgssd-timeout.patch @@ -0,0 +1,82 @@ +diff -up nfs-utils-1.3.0/utils/gssd/gssd.c.orig nfs-utils-1.3.0/utils/gssd/gssd.c +--- nfs-utils-1.3.0/utils/gssd/gssd.c.orig 2014-09-17 13:00:22.702932025 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.c 2014-09-17 13:00:26.575004049 -0400 +@@ -64,6 +64,7 @@ char *ccachesearch[GSSD_MAX_CCACHE_SEARC + int use_memcache = 0; + int root_uses_machine_creds = 1; + unsigned int context_timeout = 0; ++unsigned int rpc_timeout = 5; + char *preferred_realm = NULL; + int pipefds[2] = { -1, -1 }; + +@@ -105,7 +106,7 @@ main(int argc, char *argv[]) + char *progname; + + memset(ccachesearch, 0, sizeof(ccachesearch)); +- while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:R:")) != -1) { ++ while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { + switch (opt) { + case 'f': + fg = 1; +@@ -143,6 +144,9 @@ main(int argc, char *argv[]) + case 't': + context_timeout = atoi(optarg); + break; ++ case 'T': ++ rpc_timeout = atoi(optarg); ++ break; + case 'R': + preferred_realm = strdup(optarg); + break; +diff -up nfs-utils-1.3.0/utils/gssd/gssd.h.orig nfs-utils-1.3.0/utils/gssd/gssd.h +--- nfs-utils-1.3.0/utils/gssd/gssd.h.orig 2014-09-17 13:00:22.702932025 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.h 2014-09-17 13:00:26.575004049 -0400 +@@ -66,6 +66,7 @@ extern char *ccachesearch[]; + extern int use_memcache; + extern int root_uses_machine_creds; + extern unsigned int context_timeout; ++extern unsigned int rpc_timeout; + extern char *preferred_realm; + extern int pipefds[2]; + +diff -up nfs-utils-1.3.0/utils/gssd/gssd.man.orig nfs-utils-1.3.0/utils/gssd/gssd.man +--- nfs-utils-1.3.0/utils/gssd/gssd.man.orig 2014-09-17 13:00:22.702932025 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd.man 2014-09-17 13:00:26.575004049 -0400 +@@ -289,6 +289,14 @@ new kernel contexts to be negotiated aft + seconds, which allows changing Kerberos tickets and identities frequently. + The default is no explicit timeout, which means the kernel context will live + the lifetime of the Kerberos service ticket used in its creation. ++.TP ++.B -T timeout ++Timeout, in seconds, to create an RPC connection with a server while ++establishing an authenticated gss context for a user. ++The default timeout is set to 5 seconds. ++If you get messages like "WARNING: can't create tcp rpc_clnt to server ++%servername% for user with uid %uid%: RPC: Remote system error - ++Connection timed out", you should consider an increase of this timeout. + .SH SEE ALSO + .BR rpc.svcgssd (8), + .BR kerberos (1), +diff -up nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig nfs-utils-1.3.0/utils/gssd/gssd_proc.c +--- nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig 2014-09-17 13:00:22.702932025 -0400 ++++ nfs-utils-1.3.0/utils/gssd/gssd_proc.c 2014-09-17 13:00:26.575004049 -0400 +@@ -842,7 +842,7 @@ create_auth_rpc_client(struct clnt_info + OM_uint32 min_stat; + char rpc_errmsg[1024]; + int protocol; +- struct timeval timeout = {5, 0}; ++ struct timeval timeout; + struct sockaddr *addr = (struct sockaddr *) &clp->addr; + socklen_t salen; + +@@ -910,6 +910,10 @@ create_auth_rpc_client(struct clnt_info + if (!populate_port(addr, salen, clp->prog, clp->vers, protocol)) + goto out_fail; + ++ /* set the timeout according to the requested valued */ ++ timeout.tv_sec = (long) rpc_timeout; ++ timeout.tv_usec = (long) 0; ++ + rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog, + clp->vers, &timeout); + if (!rpc_clnt) { diff --git a/SOURCES/nfs-utils-1.3.0-rpcidmapd-usage.patch b/SOURCES/nfs-utils-1.3.0-rpcidmapd-usage.patch new file mode 100644 index 0000000..5fc918f --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-rpcidmapd-usage.patch @@ -0,0 +1,97 @@ +diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c +index aff89d1..f55d2e1 100644 +--- a/utils/idmapd/idmapd.c ++++ b/utils/idmapd/idmapd.c +@@ -199,6 +199,12 @@ flush_nfsd_idmap_cache(void) + return ret; + } + ++void usage(char *progname) ++{ ++ fprintf(stderr, "Usage: %s [-hfvCS] [-p path] [-c path]\n", ++ basename(progname)); ++} ++ + int + main(int argc, char **argv) + { +@@ -225,16 +231,18 @@ main(int argc, char **argv) + progname = argv[0]; + xlog_open(progname); + +-#define GETOPTSTR "vfd:p:U:G:c:CS" ++#define GETOPTSTR "hvfd:p:U:G:c:CS" + opterr=0; /* Turn off error messages */ + while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { + if (opt == 'c') + conf_path = optarg; + if (opt == '?') { + if (strchr(GETOPTSTR, optopt)) +- errx(1, "'-%c' option requires an argument.", optopt); ++ warnx("'-%c' option requires an argument.", optopt); + else +- errx(1, "'-%c' is an invalid argument.", optopt); ++ warnx("'-%c' is an invalid argument.", optopt); ++ usage(progname); ++ exit(1); + } + } + optind = 1; +@@ -276,6 +284,9 @@ main(int argc, char **argv) + case 'S': + clientstart = 0; + break; ++ case 'h': ++ usage(progname); ++ exit(0); + default: + break; + } +diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man +index 185cd1b..b9200c7 100644 +--- a/utils/idmapd/idmapd.man ++++ b/utils/idmapd/idmapd.man +@@ -10,8 +10,11 @@ + .Sh SYNOPSIS + .\" For a program: program [-abc] file ... + .Nm rpc.idmapd +-.Op Fl v ++.Op Fl h + .Op Fl f ++.Op Fl v ++.Op Fl C ++.Op Fl S + .Op Fl p Ar path + .Op Fl c Ar path + .Sh DESCRIPTION +@@ -20,8 +23,20 @@ is the NFSv4 ID <-> name mapping daemon. It provides functionality to + the NFSv4 kernel client and server, to which it communicates via + upcalls, by translating user and group IDs to names, and vice versa. + .Pp ++Note that on more recent kernels only the NFSv4 server uses ++.Nm . ++The NFSv4 client instead uses ++.Xr nfsidmap 8 , ++and only falls back to ++.Nm ++if there was a problem running the ++.Xr nfsidmap 8 ++program. ++.Pp + The options are as follows: + .Bl -tag -width Ds_imagedir ++.It Fl h ++Display usage message. + .It Fl v + Increases the verbosity level (can be specified multiple times). + .It Fl f +@@ -58,7 +73,8 @@ messages to console, and with a verbosity level of 3. + .Sh FILES + .Pa /etc/idmapd.conf + .Sh SEE ALSO +-.Xr idmapd.conf 5 ++.Xr idmapd.conf 5 , ++.Xr nfsidmap 8 + .\".Sh SEE ALSO + .\".Xr nylon.conf 4 + .\" .Sh COMPATIBILITY diff --git a/SOURCES/nfs-utils-1.3.0-server-generator.patch b/SOURCES/nfs-utils-1.3.0-server-generator.patch new file mode 100644 index 0000000..6f2db6c --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-server-generator.patch @@ -0,0 +1,467 @@ +diff -up nfs-utils-1.3.0/configure.ac.orig nfs-utils-1.3.0/configure.ac +--- nfs-utils-1.3.0/configure.ac.orig 2017-03-31 15:55:05.544831618 -0400 ++++ nfs-utils-1.3.0/configure.ac 2017-03-31 15:58:38.833955546 -0400 +@@ -64,8 +64,14 @@ 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 ++ if test "$withval" != "no" ; then ++ use_systemd=1 ++ if test "$withval" != "yes" ; then ++ unitdir=$withval ++ fi ++ else ++ use_systemd=0 ++ fi + ) + AM_CONDITIONAL(INSTALL_SYSTEMD, [test "$use_systemd" = 1]) + AC_SUBST(unitdir) +diff -up nfs-utils-1.3.0/.gitignore.orig nfs-utils-1.3.0/.gitignore +--- nfs-utils-1.3.0/.gitignore.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/.gitignore 2017-03-31 15:55:47.123245655 -0400 +@@ -69,6 +69,7 @@ tests/nsm_client/nlm_sm_inter_clnt.c + tests/nsm_client/nlm_sm_inter_svc.c + tests/nsm_client/nlm_sm_inter_xdr.c + utils/nfsidmap/nfsidmap ++systemd/nfs-server-generator + # cscope database files + cscope.* + # generic editor backup et al +diff -up nfs-utils-1.3.0/support/export/export.c.orig nfs-utils-1.3.0/support/export/export.c +--- nfs-utils-1.3.0/support/export/export.c.orig 2017-03-31 15:55:05.528831459 -0400 ++++ nfs-utils-1.3.0/support/export/export.c 2017-03-31 15:55:47.124245665 -0400 +@@ -15,6 +15,8 @@ + #include + #include + #include ++#include ++#include + #include "xmalloc.h" + #include "nfslib.h" + #include "exportfs.h" +@@ -68,11 +70,15 @@ static void warn_duplicated_exports(nfs_ + /** + * export_read - read entries from /etc/exports + * @fname: name of file to read from ++ * @ignore_hosts: don't check validity of host names + * + * Returns number of read entries. ++ * @ignore_hosts can be set when the host names won't be used ++ * and when getting delays or errors due to problems with ++ * hostname looking is not acceptable. + */ + int +-export_read(char *fname) ++export_read(char *fname, int ignore_hosts) + { + struct exportent *eep; + nfs_export *exp; +@@ -81,7 +87,7 @@ export_read(char *fname) + + setexportent(fname, "r"); + while ((eep = getexportent(0,1)) != NULL) { +- exp = export_lookup(eep->e_hostname, eep->e_path, 0); ++ exp = export_lookup(eep->e_hostname, eep->e_path, ignore_hosts); + if (!exp) { + if (export_create(eep, 0)) + /* possible complaints already logged */ +@@ -94,6 +100,70 @@ export_read(char *fname) + + return volumes; + } ++ ++/** ++ * export_d_read - read entries from /etc/exports. ++ * @fname: name of directory to read from ++ * @ignore_hosts: don't check validity of host names ++ * ++ * Returns number of read entries. ++ * Based on mnt_table_parse_dir() in ++ * util-linux-ng/shlibs/mount/src/tab_parse.c ++ */ ++int ++export_d_read(const char *dname, int ignore_hosts) ++{ ++ int n = 0, i; ++ struct dirent **namelist = NULL; ++ int volumes = 0; ++ ++ ++ n = scandir(dname, &namelist, NULL, versionsort); ++ if (n < 0) { ++ if (errno == ENOENT) ++ /* Silently return */ ++ return volumes; ++ xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); ++ } else if (n == 0) ++ return volumes; ++ ++ for (i = 0; i < n; i++) { ++ struct dirent *d = namelist[i]; ++ size_t namesz; ++ char fname[PATH_MAX + 1]; ++ int fname_len; ++ ++ ++ if (d->d_type != DT_UNKNOWN ++ && d->d_type != DT_REG ++ && d->d_type != DT_LNK) ++ continue; ++ if (*d->d_name == '.') ++ continue; ++ ++#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) ++ namesz = strlen(d->d_name); ++ if (!namesz ++ || namesz < _EXT_EXPORT_SIZ + 1 ++ || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), ++ _EXT_EXPORT)) ++ continue; ++ ++ fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); ++ if (fname_len > PATH_MAX) { ++ xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); ++ continue; ++ } ++ ++ volumes += export_read(fname, ignore_hosts); ++ } ++ ++ for (i = 0; i < n; i++) ++ free(namelist[i]); ++ free(namelist); ++ ++ return volumes; ++} + + /** + * export_create - create an in-core nfs_export record from an export entry +diff -up nfs-utils-1.3.0/support/include/exportfs.h.orig nfs-utils-1.3.0/support/include/exportfs.h +--- nfs-utils-1.3.0/support/include/exportfs.h.orig 2017-03-31 15:55:05.528831459 -0400 ++++ nfs-utils-1.3.0/support/include/exportfs.h 2017-03-31 15:55:47.124245665 -0400 +@@ -133,7 +133,8 @@ struct addrinfo * client_resolve(const + int client_member(const char *client, + const char *name); + +-int export_read(char *fname); ++int export_read(char *fname, int ignore_hosts); ++int export_d_read(const char *dname, int ignore_hosts); + void export_reset(nfs_export *); + nfs_export * export_lookup(char *hname, char *path, int caconical); + nfs_export * export_find(const struct addrinfo *ai, +diff -up nfs-utils-1.3.0/systemd/Makefile.am.orig nfs-utils-1.3.0/systemd/Makefile.am +--- nfs-utils-1.3.0/systemd/Makefile.am.orig 2017-03-31 15:55:05.545831628 -0400 ++++ nfs-utils-1.3.0/systemd/Makefile.am 2017-03-31 15:55:47.124245665 -0400 +@@ -4,7 +4,6 @@ MAINTAINERCLEANFILES = Makefile.in + + unit_files = \ + nfs-client.target \ +- \ + auth-rpcgss-module.service \ + nfs-blkmap.service \ + nfs-config.service \ +@@ -15,8 +14,6 @@ unit_files = \ + rpc-gssd.service \ + rpc-statd-notify.service \ + rpc-statd.service \ +- rpc-svcgssd.service \ +- \ + proc-fs-nfsd.mount \ + var-lib-nfs-rpc_pipefs.mount + +@@ -25,8 +22,16 @@ man7_MANS = nfs.systemd.man + EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS) + + unit_dir = /usr/lib/systemd/system ++generator_dir = /usr/lib/systemd/system-generators ++ ++EXTRA_PROGRAMS = nfs-server-generator ++genexecdir = $(generator_dir) ++nfs_server_generator_LDADD = ../support/export/libexport.a \ ++ ../support/nfs/libnfs.a \ ++ ../support/misc/libmisc.a + + if INSTALL_SYSTEMD ++genexec_PROGRAMS = nfs-server-generator + install-data-hook: $(unit_files) + mkdir -p $(DESTDIR)/$(unitdir) + cp $(unit_files) $(DESTDIR)/$(unitdir) +diff -up nfs-utils-1.3.0/systemd/nfs-server-generator.c.orig nfs-utils-1.3.0/systemd/nfs-server-generator.c +--- nfs-utils-1.3.0/systemd/nfs-server-generator.c.orig 2017-03-31 15:55:47.124245665 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-server-generator.c 2017-03-31 15:55:47.124245665 -0400 +@@ -0,0 +1,179 @@ ++/* ++ * nfs-server-generator: ++ * systemd generator to create ordering dependencies between ++ * nfs-server and various filesystem mounts ++ * ++ * 1/ nfs-server should start Before any 'nfs' mountpoints are ++ * mounted, in case they are loop-back mounts. This ordering is particularly ++ * important for the shutdown side, so the nfs-server is stopped ++ * after the filesystems are unmounted. ++ * 2/ nfs-server should start After all exported filesystems are mounted ++ * so there is no risk of exporting the underlying directory. ++ * This is particularly important for _net mounts which ++ * are not caught by "local-fs.target". ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "misc.h" ++#include "nfslib.h" ++#include "exportfs.h" ++ ++/* A simple "set of strings" to remove duplicates ++ * found in /etc/exports ++ */ ++struct list { ++ struct list *next; ++ char *name; ++}; ++static int is_unique(struct list **lp, char *path) ++{ ++ struct list *l = *lp; ++ ++ while (l) { ++ if (strcmp(l->name, path) == 0) ++ return 0; ++ l = l->next; ++ } ++ l = malloc(sizeof(*l)); ++ if (l == NULL) ++ return 0; ++ l->name = path; ++ l->next = *lp; ++ *lp = l; ++ return 1; ++} ++ ++/* We need to convert a path name to a systemd unit ++ * name. This requires some translation ('/' -> '-') ++ * and some escaping. ++ */ ++static void systemd_escape(FILE *f, char *path) ++{ ++ while (*path == '/') ++ path++; ++ if (!*path) { ++ /* "/" becomes "-", otherwise leading "/" is ignored */ ++ fputs("-", f); ++ return; ++ } ++ while (*path) { ++ char c = *path++; ++ ++ if (c == '/') { ++ /* multiple non-trailing slashes become '-' */ ++ while (*path == '/') ++ path++; ++ if (*path) ++ fputs("-", f); ++ } else if (isalnum(c) || c == ':' || c == '.') ++ fputc(c, f); ++ else ++ fprintf(f, "\\x%02x", c & 0xff); ++ } ++} ++ ++static int has_noauto_flag(char *path) ++{ ++ FILE *fstab; ++ struct mntent *mnt; ++ ++ fstab = setmntent("/etc/fstab", "r"); ++ if (!fstab) ++ return 0; ++ ++ while ((mnt = getmntent(fstab)) != NULL) { ++ int l = strlen(mnt->mnt_dir); ++ if (strncmp(mnt->mnt_dir, path, l) != 0) ++ continue; ++ if (path[l] && path[l] != '/') ++ continue; ++ if (hasmntopt(mnt, "noauto")) ++ break; ++ } ++ fclose(fstab); ++ return mnt != NULL; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ char *path; ++ char dirbase[] = "/nfs-server.service.d"; ++ char filebase[] = "/order-with-mounts.conf"; ++ nfs_export *exp; ++ int i; ++ struct list *list = NULL; ++ FILE *f, *fstab; ++ struct mntent *mnt; ++ ++ /* Avoid using any external services */ ++ xlog_syslog(0); ++ ++ if (argc != 4 || argv[1][0] != '/') { ++ fprintf(stderr, "nfs-server-generator: create systemd dependencies for nfs-server\n"); ++ fprintf(stderr, "Usage: normal-dir early-dir late-dir\n"); ++ exit(1); ++ } ++ ++ path = malloc(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase)); ++ if (!path) ++ exit(2); ++ if (export_read(_PATH_EXPORTS, 1) + ++ export_d_read(_PATH_EXPORTS_D, 1) == 0) ++ /* Nothing is exported, so nothing to do */ ++ exit(0); ++ ++ strcat(strcpy(path, argv[1]), dirbase); ++ mkdir(path, 0755); ++ strcat(path, filebase); ++ f = fopen(path, "w"); ++ if (!f) ++ exit(1); ++ fprintf(f, "# Automatically generated by nfs-server-generator\n\n[Unit]\n"); ++ ++ for (i = 0; i < MCL_MAXTYPES; i++) { ++ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { ++ if (!is_unique(&list, exp->m_export.e_path)) ++ continue; ++ if (exp->m_export.e_mountpoint) ++ continue; ++ if (has_noauto_flag(exp->m_export.e_path)) ++ continue; ++ if (strchr(exp->m_export.e_path, ' ')) ++ fprintf(f, "RequiresMountsFor=\"%s\"\n", ++ exp->m_export.e_path); ++ else ++ fprintf(f, "RequiresMountsFor=%s\n", ++ exp->m_export.e_path); ++ } ++ } ++ ++ fstab = setmntent("/etc/fstab", "r"); ++ if (!fstab) ++ exit(1); ++ ++ while ((mnt = getmntent(fstab)) != NULL) { ++ if (strcmp(mnt->mnt_type, "nfs") != 0 && ++ strcmp(mnt->mnt_type, "nfs4") != 0) ++ continue; ++ fprintf(f, "Before= "); ++ systemd_escape(f, mnt->mnt_dir); ++ fprintf(f, ".mount\n"); ++ } ++ ++ fclose(fstab); ++ fclose(f); ++ ++ exit(0); ++} +diff -up nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig nfs-utils-1.3.0/utils/exportfs/exportfs.c +--- nfs-utils-1.3.0/utils/exportfs/exportfs.c.orig 2017-03-31 15:55:05.553831708 -0400 ++++ nfs-utils-1.3.0/utils/exportfs/exportfs.c 2017-03-31 15:55:47.125245675 -0400 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -48,7 +47,6 @@ static void error(nfs_export *exp, int e + static void usage(const char *progname, int n); + static void validate_export(nfs_export *exp); + static int matchhostname(const char *hostname1, const char *hostname2); +-static int export_d_read(const char *dname); + static void grab_lockfile(void); + static void release_lockfile(void); + +@@ -190,8 +188,8 @@ main(int argc, char **argv) + atexit(release_lockfile); + + if (f_export && ! f_ignore) { +- if (! (export_read(_PATH_EXPORTS) + +- export_d_read(_PATH_EXPORTS_D))) { ++ if (! (export_read(_PATH_EXPORTS, 0) + ++ export_d_read(_PATH_EXPORTS_D, 0))) { + if (f_verbose) + xlog(L_WARNING, "No file systems exported!"); + } +@@ -705,63 +703,6 @@ out: + return result; + } + +-/* Based on mnt_table_parse_dir() in +- util-linux-ng/shlibs/mount/src/tab_parse.c */ +-static int +-export_d_read(const char *dname) +-{ +- int n = 0, i; +- struct dirent **namelist = NULL; +- int volumes = 0; +- +- +- n = scandir(dname, &namelist, NULL, versionsort); +- if (n < 0) { +- if (errno == ENOENT) +- /* Silently return */ +- return volumes; +- xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); +- } else if (n == 0) +- return volumes; +- +- for (i = 0; i < n; i++) { +- struct dirent *d = namelist[i]; +- size_t namesz; +- char fname[PATH_MAX + 1]; +- int fname_len; +- +- +- if (d->d_type != DT_UNKNOWN +- && d->d_type != DT_REG +- && d->d_type != DT_LNK) +- continue; +- if (*d->d_name == '.') +- continue; +- +-#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) +- namesz = strlen(d->d_name); +- if (!namesz +- || namesz < _EXT_EXPORT_SIZ + 1 +- || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), +- _EXT_EXPORT)) +- continue; +- +- fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); +- if (fname_len > PATH_MAX) { +- xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); +- continue; +- } +- +- volumes += export_read(fname); +- } +- +- for (i = 0; i < n; i++) +- free(namelist[i]); +- free(namelist); +- +- return volumes; +-} +- + static char + dumpopt(char c, char *fmt, ...) + { diff --git a/SOURCES/nfs-utils-1.3.0-start-statd-flock.patch b/SOURCES/nfs-utils-1.3.0-start-statd-flock.patch new file mode 100644 index 0000000..ee7d22b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-start-statd-flock.patch @@ -0,0 +1,27 @@ +commit 8fef90084f3d19e90ba1bb22b8cd1d58ddaf6ef3 +Author: Steve Dickson +Date: Tue Jun 21 12:06:06 2016 -0400 + + start-statd: Use flock to serialize the running of this script + + To once and for all stop multiple rpc.statd from + being started (mostly in HA environments), use + flock to serialize the running of the script + + Signed-off-by: Steve Dickson + +diff --git a/utils/statd/start-statd b/utils/statd/start-statd +index 19e6eb2..2fd6039 100755 +--- a/utils/statd/start-statd ++++ b/utils/statd/start-statd +@@ -6,6 +6,10 @@ + # site. + PATH="/sbin:/usr/sbin:/bin:/usr/bin" + ++# Use flock to serialize the running of this script ++exec 200> /var/run/rpc.statd.lock ++flock -e 200 ++ + if [ -s /var/run/rpc.statd.pid ] && + [ 1`cat /var/run/rpc.statd.pid` -gt 1 ] && + kill -0 `cat /var/run/rpc.statd.pid` > /dev/null 2>&1 diff --git a/SOURCES/nfs-utils-1.3.0-start-statd-once.patch b/SOURCES/nfs-utils-1.3.0-start-statd-once.patch new file mode 100644 index 0000000..0dc4172 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-start-statd-once.patch @@ -0,0 +1,31 @@ +diff -up nfs-utils-1.3.0/utils/statd/start-statd.orig nfs-utils-1.3.0/utils/statd/start-statd +--- nfs-utils-1.3.0/utils/statd/start-statd.orig 2016-04-14 14:16:47.608999000 -0400 ++++ nfs-utils-1.3.0/utils/statd/start-statd 2016-04-26 11:04:26.019962000 -0400 +@@ -1,4 +1,4 @@ +-#!/bin/bash -p ++#!/bin/sh + # nfsmount calls this script when mounting a filesystem with locking + # enabled, but when statd does not seem to be running (based on + # /var/run/rpc.statd.pid). +@@ -6,11 +6,19 @@ + # site. + PATH="/sbin:/usr/sbin:/bin:/usr/bin" + ++if [ -s /var/run/rpc.statd.pid ] && ++ [ 1`cat /var/run/rpc.statd.pid` -gt 1 ] && ++ kill -0 `cat /var/run/rpc.statd.pid` > /dev/null 2>&1 ++then ++ # statd already running - must have been slow to respond. ++ exit 0 ++fi + # First try systemd if it's installed. + if [ -d /run/systemd/system ]; then +- # Quit only if the call worked. +- systemctl start rpc-statd.service && exit ++ # Quit only if the call worked. ++ systemctl start rpc-statd.service && exit + fi + ++cd / + # Fall back to launching it ourselves. + exec rpc.statd --no-notify diff --git a/SOURCES/nfs-utils-1.3.0-start-statd-root.patch b/SOURCES/nfs-utils-1.3.0-start-statd-root.patch new file mode 100644 index 0000000..43277a7 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-start-statd-root.patch @@ -0,0 +1,35 @@ +diff --git a/utils/mount/network.c b/utils/mount/network.c +index 4f8c15c..515249b 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -796,6 +796,8 @@ int start_statd(void) + if (stat(START_STATD, &stb) == 0) { + if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) { + int cnt = STATD_TIMEOUT * 10; ++ int status = 0; ++ char * const envp[1] = { NULL }; + const struct timespec ts = { + .tv_sec = 0, + .tv_nsec = 100000000, +@@ -803,14 +805,19 @@ int start_statd(void) + pid_t pid = fork(); + switch (pid) { + case 0: /* child */ +- execl(START_STATD, START_STATD, NULL); ++ setgid(0); ++ setuid(0); ++ execle(START_STATD, START_STATD, NULL, envp); + exit(1); + case -1: /* error */ + nfs_error(_("%s: fork failed: %s"), + progname, strerror(errno)); + break; + default: /* parent */ +- waitpid(pid, NULL,0); ++ if (waitpid(pid, &status,0) == pid && ++ status == 0) ++ /* assume it worked */ ++ return 1; + break; + } + while (1) { diff --git a/SOURCES/nfs-utils-1.3.0-startstatd-systemd.patch b/SOURCES/nfs-utils-1.3.0-startstatd-systemd.patch new file mode 100644 index 0000000..778908f --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-startstatd-systemd.patch @@ -0,0 +1,14 @@ +diff -up nfs-utils-1.3.0/utils/statd/start-statd.orig nfs-utils-1.3.0/utils/statd/start-statd +--- nfs-utils-1.3.0/utils/statd/start-statd.orig 2014-09-30 09:17:31.000000000 -0400 ++++ nfs-utils-1.3.0/utils/statd/start-statd 2014-09-30 09:15:01.000000000 -0400 +@@ -5,8 +5,9 @@ + # It should run statd with whatever flags are apropriate for this + # site. + PATH="/sbin:/usr/sbin:/bin:/usr/bin" +-if systemctl start statd.service ++if systemctl start rpc-statd.service + then : + else + exec rpc.statd --no-notify + fi ++ diff --git a/SOURCES/nfs-utils-1.3.0-statd-callback.patch b/SOURCES/nfs-utils-1.3.0-statd-callback.patch new file mode 100644 index 0000000..dbaf087 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-statd-callback.patch @@ -0,0 +1,86 @@ +diff -up nfs-utils-1.3.0/utils/statd/callback.c.orig nfs-utils-1.3.0/utils/statd/callback.c +--- nfs-utils-1.3.0/utils/statd/callback.c.orig 2014-09-17 13:39:01.009781560 -0400 ++++ nfs-utils-1.3.0/utils/statd/callback.c 2014-09-17 13:39:07.217896069 -0400 +@@ -10,11 +10,13 @@ + #include + #endif + ++#include + #include + + #include "rpcmisc.h" + #include "statd.h" + #include "notlist.h" ++#include "ha-callout.h" + + /* Callback notify list. */ + /* notify_list *cbnl = NULL; ... never used */ +@@ -87,6 +89,13 @@ sm_notify_1_svc(struct stat_chge *argp, + xlog(D_CALL, "Received SM_NOTIFY from %s, state: %d", + argp->mon_name, argp->state); + ++ if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) { ++ xlog_warn("Unrecognized sender address"); ++ return ((void *) &result); ++ } ++ ++ ha_callout("sm-notify", argp->mon_name, ip_addr, argp->state); ++ + /* quick check - don't bother if we're not monitoring anyone */ + if (rtnl == NULL) { + xlog_warn("SM_NOTIFY from %s while not monitoring any hosts", +@@ -94,11 +103,6 @@ sm_notify_1_svc(struct stat_chge *argp, + return ((void *) &result); + } + +- if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) { +- xlog_warn("Unrecognized sender address"); +- return ((void *) &result); +- } +- + /* okir change: statd doesn't remove the remote host from its + * internal monitor list when receiving an SM_NOTIFY call from + * it. Lockd will want to continue monitoring the remote host +diff -up nfs-utils-1.3.0/utils/statd/statd.man.orig nfs-utils-1.3.0/utils/statd/statd.man +--- nfs-utils-1.3.0/utils/statd/statd.man.orig 2014-09-17 13:39:01.009781560 -0400 ++++ nfs-utils-1.3.0/utils/statd/statd.man 2014-09-17 13:39:07.217896069 -0400 +@@ -346,7 +346,8 @@ points due to inactivity. + .SS High-availability callouts + .B rpc.statd + can exec a special callout program during processing of +-successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests. ++successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests, ++or when it receives SM_NOTIFY. + Such a program may be used in High Availability NFS (HA-NFS) + environments to track lock state that may need to be migrated after + a system reboot. +@@ -357,15 +358,26 @@ option. + The program is run with 3 arguments: + The first is either + .B add-client +-or + .B del-client ++or ++.B sm-notify + depending on the reason for the callout. + The second is the + .I mon_name + of the monitored peer. + The third is the +-.I caller_name +-of the requesting lock manager. ++.I caller_name ++of the requesting lock manager for ++.B add-client ++or ++.B del-client ++, otherwise it is ++.I IP_address ++of the caller sending SM_NOTIFY. ++The forth is the ++.I state_value ++in the SM_NOTIFY request. ++ + .SS IPv6 and TI-RPC support + TI-RPC is a pre-requisite for supporting NFS on IPv6. + If TI-RPC support is built into diff --git a/SOURCES/nfs-utils-1.3.0-statd-monlists.patch b/SOURCES/nfs-utils-1.3.0-statd-monlists.patch new file mode 100644 index 0000000..77b2195 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-statd-monlists.patch @@ -0,0 +1,95 @@ +commit 76f8ce8ce02868490ddfc5686bd48562fa73eab1 +Author: Scott Mayhew +Date: Mon Nov 23 10:43:03 2015 -0500 + + statd: Update existing record if we receive SM_MON with new cookie + + This prevents rpc.statd's in-memory (and on-disk) monitor lists from + winding up with multiple records for the same peer with outdated + cookie values. This happens in some HA-NFS configurations where + rpc.statd is always running. + + Signed-off-by: Scott Mayhew + Signed-off-by: Steve Dickson + +diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c +index 286a5e2..368bd80 100644 +--- a/utils/statd/monitor.c ++++ b/utils/statd/monitor.c +@@ -72,6 +72,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; + char *dnsname = NULL; ++ int existing = 0; + + xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name); + +@@ -148,17 +149,26 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) + if (statd_matchhostname(NL_MY_NAME(clnt), my_name) && + NL_MY_PROC(clnt) == id->my_proc && + NL_MY_PROG(clnt) == id->my_prog && +- NL_MY_VERS(clnt) == id->my_vers && +- memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) { +- /* Hey! We already know you guys! */ +- xlog(D_GENERAL, +- "Duplicate SM_MON request for %s " +- "from procedure on %s", +- mon_name, my_name); ++ NL_MY_VERS(clnt) == id->my_vers) { ++ if (memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE)) { ++ xlog(D_GENERAL, ++ "Received SM_MON request with new " ++ "cookie for %s from procedure on %s", ++ mon_name, my_name); ++ ++ existing = 1; ++ break; ++ } else { ++ /* Hey! We already know you guys! */ ++ xlog(D_GENERAL, ++ "Duplicate SM_MON request for %s " ++ "from procedure on %s", ++ mon_name, my_name); + +- /* But we'll let you pass anyway. */ +- free(dnsname); +- goto success; ++ /* But we'll let you pass anyway. */ ++ free(dnsname); ++ goto success; ++ } + } + clnt = NL_NEXT(clnt); + } +@@ -167,7 +177,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) + * We're committed...ignoring errors. Let's hope that a malloc() + * doesn't fail. (I should probably fix this assumption.) + */ +- if (!(clnt = nlist_new(my_name, mon_name, 0))) { ++ if (!existing && !(clnt = nlist_new(my_name, mon_name, 0))) { + free(dnsname); + xlog_warn("out of memory"); + goto failure; +@@ -180,8 +190,11 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) + clnt->dns_name = dnsname; + + /* +- * Now, Create file on stable storage for host. ++ * Now, Create file on stable storage for host, first deleting any ++ * existing records on file. + */ ++ nsm_delete_monitored_host(dnsname, mon_name, my_name); ++ + if (!nsm_insert_monitored_host(dnsname, + (struct sockaddr *)(char *)&my_addr, argp)) { + nlist_free(NULL, clnt); +@@ -190,7 +203,8 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) + + /* PRC: do the HA callout: */ + ha_callout("add-client", mon_name, my_name, -1); +- nlist_insert(&rtnl, clnt); ++ if (!existing) ++ nlist_insert(&rtnl, clnt); + xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name); + success: + result.res_stat = STAT_SUCC; diff --git a/SOURCES/nfs-utils-1.3.0-statd-notify-grace-period.patch b/SOURCES/nfs-utils-1.3.0-statd-notify-grace-period.patch new file mode 100644 index 0000000..3ff539d --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-statd-notify-grace-period.patch @@ -0,0 +1,167 @@ +diff --git a/nfs.conf b/nfs.conf +new file mode 100644 +index 0000000..690645c +--- /dev/null ++++ b/nfs.conf +@@ -0,0 +1,71 @@ ++# ++# This is a general conifguration for the ++# NFS daemons and tools ++# ++#[exportfs] ++# debug=0 ++# ++#[gssd] ++# use-memcache=0 ++# use-machine-creds=1 ++# avoid-dns=1 ++# limit-to-legacy-enctypes=0 ++# context-timeout=0 ++# rpc-timeout=5 ++# pipefs-directory=/var/lib/nfs/rpc_pipefs ++# keytab-file=/etc/krb5.keytab ++# cred-cache-directory= ++# preferred-realm= ++# ++#[lockd] ++# port=0 ++# udp-port=0 ++# ++#[mountd] ++# debug=0 ++# manage_gids=n ++# descriptors=0 ++# port=0 ++# threads=1 ++# reverse-lookup=n ++# state-directory-path=/var/lib/nfs ++# ha-callout= ++# ++#[nfsdcltrack] ++# debug=0 ++# storagedir=/var/lib/nfs/nfsdcltrack ++# ++#[nfsd] ++# debug=0 ++# threads=8 ++# host= ++# port=0 ++# grace-time=90 ++# lease-time=90 ++# udp=y ++# tcp=y ++# vers2=n ++# vers3=y ++# vers4=y ++# vers4.0=y ++# vers4.1=y ++# vers4.2=y ++# rdma=n ++# ++#[statd] ++# debug=0 ++# port=0 ++# outgoing-port=0 ++# name= ++# state-directory-path=/var/lib/nfs/statd ++# ha-callout= ++# ++#[sm-notify] ++# debug=0 ++# retry-time=900 ++# outgoing-port= ++# outgoing-addr= ++# lift-grace=y ++# ++#[svcgssd] ++# principal= +diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c +index dcb85a3..ec59311 100644 +--- a/utils/statd/sm-notify.c ++++ b/utils/statd/sm-notify.c +@@ -46,6 +46,10 @@ + #define NSM_TIMEOUT 2 + #define NSM_MAX_TIMEOUT 120 /* don't make this too big */ + ++#define NLM_END_GRACE_FILE "/proc/fs/lockd/nlm_end_grace" ++ ++int lift_grace = 1; ++ + struct nsm_host { + struct nsm_host * next; + char * name; +@@ -456,6 +460,28 @@ retry: + return sock; + } + ++/* Inform the kernel that it's OK to lift lockd's grace period */ ++static void ++nsm_lift_grace_period(void) ++{ ++ int fd; ++ ++ fd = open(NLM_END_GRACE_FILE, O_WRONLY); ++ if (fd < 0) { ++ /* Don't warn if file isn't present */ ++ if (errno != ENOENT) ++ xlog(L_WARNING, "Unable to open %s: %m", ++ NLM_END_GRACE_FILE); ++ return; ++ } ++ ++ if (write(fd, "Y", 1) < 0) ++ xlog(L_WARNING, "Unable to write to %s: %m", NLM_END_GRACE_FILE); ++ ++ close(fd); ++ return; ++} ++ + int + main(int argc, char **argv) + { +@@ -474,6 +500,7 @@ main(int argc, char **argv) + opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60; + opt_srcport = conf_get_str("sm-notify", "outgoing-port"); + opt_srcaddr = conf_get_str("sm-notify", "outgoing-addr"); ++ lift_grace = conf_get_bool("sm-notify", "lift-grace", lift_grace); + s = conf_get_str("statd", "state-directory-path"); + if (s && !nsm_setup_pathnames(argv[0], s)) + exit(1); +@@ -550,6 +577,8 @@ usage: fprintf(stderr, + (void)nsm_retire_monitored_hosts(); + if (nsm_load_notify_list(smn_get_host) == 0) { + xlog(D_GENERAL, "No hosts to notify; exiting"); ++ if (lift_grace) ++ nsm_lift_grace_period(); + return 0; + } + +diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man +index 89627e5..4658d86 100644 +--- a/utils/statd/sm-notify.man ++++ b/utils/statd/sm-notify.man +@@ -241,6 +241,24 @@ These have the same effect as the command line options + .B v + respectively. + ++An additional value recognized in the ++.B [sm-notify] ++section is ++.BR lift-grace . ++By default, ++.B sm-notify ++will lift lockd's grace period early if it has no hosts to notify. ++Some high availability configurations will run one ++.B sm-notify ++per floating IP address. In these configurations, lifting the ++grace period early may prevent clients from reclaiming locks. ++.RB "Setting " lift-grace " to " n ++will prevent ++.B sm-notify ++from ending the grace period early. ++.B lift-grace ++has no corresponding command line option. ++ + The value recognized in the + .B [statd] + section is diff --git a/SOURCES/nfs-utils-1.3.0-statd-warnings.patch b/SOURCES/nfs-utils-1.3.0-statd-warnings.patch new file mode 100644 index 0000000..f7cfae3 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-statd-warnings.patch @@ -0,0 +1,91 @@ +diff -up nfs-utils-1.3.0/support/include/nsm.h.orig nfs-utils-1.3.0/support/include/nsm.h +--- nfs-utils-1.3.0/support/include/nsm.h.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/include/nsm.h 2016-06-23 10:09:34.216841414 -0400 +@@ -59,7 +59,8 @@ extern unsigned int + extern _Bool nsm_insert_monitored_host(const char *hostname, + const struct sockaddr *sap, const struct mon *m); + extern void nsm_delete_monitored_host(const char *hostname, +- const char *mon_name, const char *my_name); ++ const char *mon_name, const char *my_name, ++ const int chatty); + extern void nsm_delete_notified_host(const char *hostname, + const char *mon_name, const char *my_name); + extern size_t nsm_priv_to_hex(const char *priv, char *buf, +diff -up nfs-utils-1.3.0/support/nsm/file.c.orig nfs-utils-1.3.0/support/nsm/file.c +--- nfs-utils-1.3.0/support/nsm/file.c.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/support/nsm/file.c 2016-06-23 10:09:34.216841414 -0400 +@@ -1012,7 +1012,7 @@ nsm_load_notify_list(nsm_populate_t func + + static void + nsm_delete_host(const char *directory, const char *hostname, +- const char *mon_name, const char *my_name) ++ const char *mon_name, const char *my_name, const int chatty) + { + char line[LINELEN + 1 + SM_MAXSTRLEN + 2]; + char *outbuf = NULL; +@@ -1028,8 +1028,9 @@ nsm_delete_host(const char *directory, c + } + + if (stat(path, &stb) == -1) { +- xlog(L_ERROR, "Failed to delete: " +- "could not stat original file %s: %m", path); ++ if (chatty) ++ xlog(L_ERROR, "Failed to delete: " ++ "could not stat original file %s: %m", path); + goto out; + } + remaining = (size_t)stb.st_size + 1; +@@ -1108,13 +1109,14 @@ out: + * @hostname: '\0'-terminated C string containing hostname of record to delete + * @mon_name: '\0'-terminated C string containing monname of record to delete + * @my_name: '\0'-terminated C string containing myname of record to delete ++ * @chatty: should an error be logged if the monitor file doesn't exist? + * + */ + void + nsm_delete_monitored_host(const char *hostname, const char *mon_name, +- const char *my_name) ++ const char *my_name, const int chatty) + { +- nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name); ++ nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name, chatty); + } + + /** +@@ -1128,5 +1130,5 @@ void + nsm_delete_notified_host(const char *hostname, const char *mon_name, + const char *my_name) + { +- nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name); ++ nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name, 1); + } +diff -up nfs-utils-1.3.0/utils/statd/monitor.c.orig nfs-utils-1.3.0/utils/statd/monitor.c +--- nfs-utils-1.3.0/utils/statd/monitor.c.orig 2016-06-23 10:08:34.442835693 -0400 ++++ nfs-utils-1.3.0/utils/statd/monitor.c 2016-06-23 10:09:34.216841414 -0400 +@@ -193,7 +193,7 @@ sm_mon_1_svc(struct mon *argp, struct sv + * Now, Create file on stable storage for host, first deleting any + * existing records on file. + */ +- nsm_delete_monitored_host(dnsname, mon_name, my_name); ++ nsm_delete_monitored_host(dnsname, mon_name, my_name, 0); + + if (!nsm_insert_monitored_host(dnsname, + (struct sockaddr *)(char *)&my_addr, argp)) { +@@ -324,7 +324,7 @@ sm_unmon_1_svc(struct mon_id *argp, stru + ha_callout("del-client", mon_name, my_name, -1); + + nsm_delete_monitored_host(clnt->dns_name, +- mon_name, my_name); ++ mon_name, my_name, 1); + nlist_free(&rtnl, clnt); + + return (&result); +@@ -379,7 +379,7 @@ sm_unmon_all_1_svc(struct my_id *argp, s + /* PRC: do the HA callout: */ + ha_callout("del-client", mon_name, my_name, -1); + nsm_delete_monitored_host(clnt->dns_name, +- mon_name, my_name); ++ mon_name, my_name, 1); + nlist_free(&rtnl, clnt); + ++count; + clnt = temp; diff --git a/SOURCES/nfs-utils-1.3.0-systemd-args.patch b/SOURCES/nfs-utils-1.3.0-systemd-args.patch new file mode 100644 index 0000000..45a0a58 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-args.patch @@ -0,0 +1,9 @@ +diff -up nfs-utils-1.3.0/systemd/nfs-blkmap.service.orig nfs-utils-1.3.0/systemd/nfs-blkmap.service +--- nfs-utils-1.3.0/systemd/nfs-blkmap.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-blkmap.service 2014-12-09 13:25:56.145156424 -0500 +@@ -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/SOURCES/nfs-utils-1.3.0-systemd-config.patch b/SOURCES/nfs-utils-1.3.0-systemd-config.patch new file mode 100644 index 0000000..6f1ba46 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-config.patch @@ -0,0 +1,37 @@ +commit c4940fad2a73481cad67732746a4e2bb74e8d32e +Author: NeilBrown +Date: Wed Mar 16 12:18:40 2016 -0400 + + systemd: ensure nfs-config service is re-run as needed. + + The nfs-config service translates distro-specific startup + configuration into "environment" variable read and used + by systemd unit files. + + Currently it is only run once, so subsequent changes to the + distro-specific files do not take effect when an nfs service is + restarted. + + If we change "RemainAfterExit=yes" to "RemainAfterExit=no" then the + service will be restarted before any dependant service is started, so + the environment file will always be up to date. + + Reported-and-tested-by: Benjamin Coddington + Signed-off-by: NeilBrown + Signed-off-by: Steve Dickson + +diff --git a/systemd/nfs-config.service b/systemd/nfs-config.service +index 7f65305..4b206b5 100644 +--- a/systemd/nfs-config.service ++++ b/systemd/nfs-config.service +@@ -5,5 +5,9 @@ DefaultDependencies=no + + [Service] + Type=oneshot +-RemainAfterExit=yes ++# This service needs to run any time any nfs service ++# is started, so changes to local config files get ++# incorporated. Having "RemainAfterExit=no" (the default) ++# ensures this happens. ++RemainAfterExit=no + ExecStart=/usr/lib/systemd/scripts/nfs-utils_env.sh diff --git a/SOURCES/nfs-utils-1.3.0-systemd-decouple.patch b/SOURCES/nfs-utils-1.3.0-systemd-decouple.patch new file mode 100644 index 0000000..83805ef --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-decouple.patch @@ -0,0 +1,24 @@ +diff -up nfs-utils-1.3.0/systemd/nfs-server.service.orig nfs-utils-1.3.0/systemd/nfs-server.service +--- nfs-utils-1.3.0/systemd/nfs-server.service.orig 2015-09-29 16:45:31.998991287 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-server.service 2015-09-29 16:55:00.386866977 -0400 +@@ -1,7 +1,7 @@ + [Unit] + Description=NFS server and services + DefaultDependencies=no +-Requires= network.target proc-fs-nfsd.mount rpcbind.service ++Requires= network.target proc-fs-nfsd.mount rpcbind.target + Requires= nfs-mountd.service + Wants=rpc-statd.service nfs-idmapd.service + Wants=rpc-statd-notify.service +diff -up nfs-utils-1.3.0/systemd/rpc-statd.service.orig nfs-utils-1.3.0/systemd/rpc-statd.service +--- nfs-utils-1.3.0/systemd/rpc-statd.service.orig 2015-09-29 16:45:31.999991304 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-statd.service 2015-09-29 16:55:30.766394792 -0400 +@@ -2,7 +2,7 @@ + Description=NFS status monitor for NFSv2/3 locking. + DefaultDependencies=no + Conflicts=umount.target +-Requires=nss-lookup.target rpcbind.service ++Requires=nss-lookup.target rpcbind.target + After=network.target nss-lookup.target rpcbind.service + + PartOf=nfs-utils.service diff --git a/SOURCES/nfs-utils-1.3.0-systemd-gssproxy.patch b/SOURCES/nfs-utils-1.3.0-systemd-gssproxy.patch new file mode 100644 index 0000000..77dc453 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-gssproxy.patch @@ -0,0 +1,77 @@ +diff -up nfs-utils-1.3.0/systemd/auth-rpcgss-module.service.orig nfs-utils-1.3.0/systemd/auth-rpcgss-module.service +--- nfs-utils-1.3.0/systemd/auth-rpcgss-module.service.orig 2017-05-22 11:22:16.064030000 -0400 ++++ nfs-utils-1.3.0/systemd/auth-rpcgss-module.service 2017-06-06 16:19:05.229155456 -0400 +@@ -7,8 +7,8 @@ + [Unit] + Description=Kernel Module supporting RPCSEC_GSS + DefaultDependencies=no +-Before=gssproxy.service rpc-svcgssd.service rpc-gssd.service +-Wants=gssproxy.service rpc-svcgssd.service rpc-gssd.service ++Before=gssproxy.service rpc-gssd.service ++Wants=gssproxy.service rpc-gssd.service + ConditionPathExists=/etc/krb5.keytab + + [Service] +diff -up nfs-utils-1.3.0/systemd/nfs-client.target.orig nfs-utils-1.3.0/systemd/nfs-client.target +--- nfs-utils-1.3.0/systemd/nfs-client.target.orig 2017-05-22 11:22:16.054029846 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-client.target 2017-06-06 16:19:26.653588268 -0400 +@@ -9,7 +9,7 @@ Wants=rpc-statd-notify.service + + # GSS services dependencies and ordering + Wants=auth-rpcgss-module.service +-After=rpc-gssd.service rpc-svcgssd.service gssproxy.service ++After=rpc-gssd.service gssproxy.service + + [Install] + WantedBy=multi-user.target +diff -up nfs-utils-1.3.0/systemd/nfs.conf.man.orig nfs-utils-1.3.0/systemd/nfs.conf.man +--- nfs-utils-1.3.0/systemd/nfs.conf.man.orig 2017-05-22 11:22:16.118030830 -0400 ++++ nfs-utils-1.3.0/systemd/nfs.conf.man 2017-06-06 16:20:11.502494296 -0400 +@@ -208,15 +208,6 @@ See + for details. + + .TP +-.B svcgssd +-Recognized values: +-.BR principal . +- +-See +-.BR rpc.svcgssd (8) +-for details. +- +-.TP + .B exportfs + Only + .B debug= +diff -up nfs-utils-1.3.0/systemd/nfs-server.service.orig nfs-utils-1.3.0/systemd/nfs-server.service +--- nfs-utils-1.3.0/systemd/nfs-server.service.orig 2017-05-22 11:22:16.138031137 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-server.service 2017-06-06 16:16:55.197527187 -0400 +@@ -14,7 +14,7 @@ Before= rpc-statd-notify.service + + # GSS services dependencies and ordering + Wants=auth-rpcgss-module.service +-After=rpc-gssd.service gssproxy.service rpc-svcgssd.service ++After=rpc-gssd.service gssproxy.service + + Wants=nfs-config.service + After=nfs-config.service +@@ -25,6 +25,7 @@ EnvironmentFile=-/run/sysconfig/nfs-util + Type=oneshot + RemainAfterExit=yes + ExecStartPre=-/usr/sbin/exportfs -r ++ExecStartPre=-/bin/sh -c '/bin/kill -HUP `cat /run/gssproxy.pid`' + ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS + ExecStop=/usr/sbin/rpc.nfsd 0 + ExecStopPost=/usr/sbin/exportfs -au +diff -up nfs-utils-1.3.0/systemd/rpc-gssd.service.orig nfs-utils-1.3.0/systemd/rpc-gssd.service +--- nfs-utils-1.3.0/systemd/rpc-gssd.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-gssd.service 2017-06-06 16:24:08.932290804 -0400 +@@ -3,7 +3,7 @@ Description=RPC security service for NFS + DefaultDependencies=no + Conflicts=umount.target + Requires=var-lib-nfs-rpc_pipefs.mount +-After=var-lib-nfs-rpc_pipefs.mount ++After=var-lib-nfs-rpc_pipefs.mount gssproxy.service + + ConditionPathExists=/etc/krb5.keytab + diff --git a/SOURCES/nfs-utils-1.3.0-systemd-ha-nonotify.patch b/SOURCES/nfs-utils-1.3.0-systemd-ha-nonotify.patch new file mode 100644 index 0000000..888a181 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-ha-nonotify.patch @@ -0,0 +1,13 @@ +diff -up nfs-utils-1.3.0/systemd/rpc-statd-notify.service.org nfs-utils-1.3.0/systemd/rpc-statd-notify.service +--- nfs-utils-1.3.0/systemd/rpc-statd-notify.service.org 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-statd-notify.service 2015-01-22 11:13:28.000000000 -0500 +@@ -3,6 +3,9 @@ Description=Notify NFS peers of a restar + Requires=network-online.target + After=network-online.target nss-lookup.target + ++# Do not start up in HA environments ++ConditionPathExists=!/var/lib/nfs/statd/sm.ha ++ + # if we run an nfs server, it needs to be running before we + # tell clients that it has restarted. + After=nfs-server.service diff --git a/SOURCES/nfs-utils-1.3.0-systemd-idmapd-varlib.patch b/SOURCES/nfs-utils-1.3.0-systemd-idmapd-varlib.patch new file mode 100644 index 0000000..8ef0518 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-idmapd-varlib.patch @@ -0,0 +1,25 @@ +commit 6efdb0440daf3ed304a3c1115f01e76e89d792a7 +Author: Chris Mayo +Date: Fri Jan 23 10:35:32 2015 -0500 + + systemd: Ensure RPC pipefs is mounted before rpc.idmapd starts + + rpc.idmapd aborts on start-up if RPC pipefs is not present. + + Needed if GSS services are not used. + + Signed-off-by: Chris Mayo + Signed-off-by: Steve Dickson + +diff --git a/systemd/nfs-idmapd.service b/systemd/nfs-idmapd.service +index 726038d..e84f8c8 100644 +--- a/systemd/nfs-idmapd.service ++++ b/systemd/nfs-idmapd.service +@@ -1,5 +1,7 @@ + [Unit] + Description=NFSv4 ID-name mapping service ++Requires=var-lib-nfs-rpc_pipefs.mount ++After=var-lib-nfs-rpc_pipefs.mount + + BindsTo=nfs-server.service + diff --git a/SOURCES/nfs-utils-1.3.0-systemd-idmapd.patch b/SOURCES/nfs-utils-1.3.0-systemd-idmapd.patch new file mode 100644 index 0000000..fde4aa1 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-idmapd.patch @@ -0,0 +1,57 @@ +diff -up nfs-utils-1.3.0/systemd/nfs-idmapd.service.orig nfs-utils-1.3.0/systemd/nfs-idmapd.service +--- nfs-utils-1.3.0/systemd/nfs-idmapd.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-idmapd.service 2015-01-15 08:04:55.291478000 -0500 +@@ -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 -up nfs-utils-1.3.0/systemd/nfs-mountd.service.orig nfs-utils-1.3.0/systemd/nfs-mountd.service +--- nfs-utils-1.3.0/systemd/nfs-mountd.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-mountd.service 2015-01-15 08:04:55.300477000 -0500 +@@ -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 -up nfs-utils-1.3.0/systemd/rpc-statd-notify.service.orig nfs-utils-1.3.0/systemd/rpc-statd-notify.service +--- nfs-utils-1.3.0/systemd/rpc-statd-notify.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-statd-notify.service 2015-01-15 08:06:17.251900000 -0500 +@@ -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 -up nfs-utils-1.3.0/utils/statd/start-statd.orig nfs-utils-1.3.0/utils/statd/start-statd +--- nfs-utils-1.3.0/utils/statd/start-statd.orig 2015-01-15 08:03:24.456789000 -0500 ++++ nfs-utils-1.3.0/utils/statd/start-statd 2015-01-15 08:05:34.612638000 -0500 +@@ -5,9 +5,12 @@ + # It should run statd with whatever flags are apropriate for this + # site. + PATH="/sbin:/usr/sbin:/bin:/usr/bin" +-if systemctl start rpc-statd.service +-then : +-else +- exec rpc.statd --no-notify ++ ++# First try systemd if it's installed. ++if [ -d /run/systemd/system ]; then ++ # Quit only if the call worked. ++ systemctl start rpc-statd.service && exit + fi + ++# Fall back to launching it ourselves. ++exec rpc.statd --no-notify diff --git a/SOURCES/nfs-utils-1.3.0-systemd-network-online.patch b/SOURCES/nfs-utils-1.3.0-systemd-network-online.patch new file mode 100644 index 0000000..07cb8ca --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-network-online.patch @@ -0,0 +1,69 @@ +diff --git a/systemd/nfs-mountd.service b/systemd/nfs-mountd.service +index 8a39f3e..ed357a2 100644 +--- a/systemd/nfs-mountd.service ++++ b/systemd/nfs-mountd.service +@@ -2,8 +2,10 @@ + Description=NFS Mount Daemon + DefaultDependencies=no + Requires=proc-fs-nfsd.mount ++Wants=network-online.target + After=proc-fs-nfsd.mount +-After=network.target local-fs.target ++After=network-online.target local-fs.target ++After=rpcbind.socket + BindsTo=nfs-server.service + + Wants=nfs-config.service +diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service +index 7f60f39..d285c6e 100644 +--- a/systemd/nfs-server.service ++++ b/systemd/nfs-server.service +@@ -1,13 +1,14 @@ + [Unit] + Description=NFS server and services + DefaultDependencies=no +-Requires= network.target proc-fs-nfsd.mount rpcbind.target ++Requires= network.target proc-fs-nfsd.mount + Requires= nfs-mountd.service ++Wants=rpcbind.socket network-online.target + Wants=rpc-statd.service nfs-idmapd.service + Wants=rpc-statd-notify.service + +-After= local-fs.target +-After= network.target proc-fs-nfsd.mount rpcbind.service nfs-mountd.service ++After= network-online.target local-fs.target ++After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service + After= nfs-idmapd.service rpc-statd.service + Before= rpc-statd-notify.service + +diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service +index 7a37ce1..f27f76d 100644 +--- a/systemd/rpc-statd-notify.service ++++ b/systemd/rpc-statd-notify.service +@@ -1,8 +1,8 @@ + [Unit] + Description=Notify NFS peers of a restart + DefaultDependencies=no +-Requires=network.target +-After=local-fs.target network.target nss-lookup.target ++Wants=network-online.target ++After=local-fs.target network-online.target nss-lookup.target + + # Do not start up in HA environments + ConditionPathExists=!/var/lib/nfs/statd/sm.ha +diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service +index 2a054be..1ed60a8 100644 +--- a/systemd/rpc-statd.service ++++ b/systemd/rpc-statd.service +@@ -2,8 +2,9 @@ + Description=NFS status monitor for NFSv2/3 locking. + DefaultDependencies=no + Conflicts=umount.target +-Requires=nss-lookup.target rpcbind.target +-After=network.target nss-lookup.target rpcbind.service ++Requires=nss-lookup.target rpcbind.socket ++Wants=network-online.target ++After=network-online.target nss-lookup.target rpcbind.socket + + PartOf=nfs-utils.service + diff --git a/SOURCES/nfs-utils-1.3.0-systemd-rpcbind.patch b/SOURCES/nfs-utils-1.3.0-systemd-rpcbind.patch new file mode 100644 index 0000000..4d7d2b8 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-rpcbind.patch @@ -0,0 +1,109 @@ +diff -up nfs-utils-1.3.0/systemd/auth-rpcgss-module.service.orig nfs-utils-1.3.0/systemd/auth-rpcgss-module.service +--- nfs-utils-1.3.0/systemd/auth-rpcgss-module.service.orig 2015-06-25 15:01:27.650527038 -0400 ++++ nfs-utils-1.3.0/systemd/auth-rpcgss-module.service 2015-06-25 15:01:45.166856358 -0400 +@@ -6,6 +6,7 @@ + # unit will fail. But that's OK.) + [Unit] + Description=Kernel Module supporting RPCSEC_GSS ++DefaultDependencies=no + Before=gssproxy.service rpc-svcgssd.service rpc-gssd.service + Wants=gssproxy.service rpc-svcgssd.service rpc-gssd.service + ConditionPathExists=/etc/krb5.keytab +diff -up nfs-utils-1.3.0/systemd/nfs-config.service.orig nfs-utils-1.3.0/systemd/nfs-config.service +--- nfs-utils-1.3.0/systemd/nfs-config.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-config.service 2015-06-25 15:01:45.166856358 -0400 +@@ -1,5 +1,7 @@ + [Unit] + Description=Preprocess NFS configuration ++After=local-fs.target ++DefaultDependencies=no + + [Service] + Type=oneshot +diff -up nfs-utils-1.3.0/systemd/nfs-idmapd.service.orig nfs-utils-1.3.0/systemd/nfs-idmapd.service +--- nfs-utils-1.3.0/systemd/nfs-idmapd.service.orig 2015-06-25 15:01:27.663527282 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-idmapd.service 2015-06-25 15:01:45.166856358 -0400 +@@ -1,7 +1,8 @@ + [Unit] + Description=NFSv4 ID-name mapping service ++DefaultDependencies=no + Requires=var-lib-nfs-rpc_pipefs.mount +-After=var-lib-nfs-rpc_pipefs.mount ++After=var-lib-nfs-rpc_pipefs.mount local-fs.target + + BindsTo=nfs-server.service + +diff -up nfs-utils-1.3.0/systemd/nfs-mountd.service.orig nfs-utils-1.3.0/systemd/nfs-mountd.service +--- nfs-utils-1.3.0/systemd/nfs-mountd.service.orig 2015-06-25 15:01:27.657527169 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-mountd.service 2015-06-25 15:01:45.166856358 -0400 +@@ -1,8 +1,9 @@ + [Unit] + Description=NFS Mount Daemon ++DefaultDependencies=no + Requires=proc-fs-nfsd.mount + After=proc-fs-nfsd.mount +-After=network.target ++After=network.target local-fs.target + BindsTo=nfs-server.service + + Wants=nfs-config.service +diff -up nfs-utils-1.3.0/systemd/nfs-server.service.orig nfs-utils-1.3.0/systemd/nfs-server.service +--- nfs-utils-1.3.0/systemd/nfs-server.service.orig 2015-06-25 15:01:45.166856358 -0400 ++++ nfs-utils-1.3.0/systemd/nfs-server.service 2015-06-25 15:02:29.916697572 -0400 +@@ -1,11 +1,13 @@ + [Unit] + Description=NFS server and services +-Requires= network.target proc-fs-nfsd.mount rpcbind.target ++DefaultDependencies=no ++Requires= network.target proc-fs-nfsd.mount rpcbind.service + Requires= nfs-mountd.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= local-fs.target ++After= network.target proc-fs-nfsd.mount rpcbind.service nfs-mountd.service + After= nfs-idmapd.service rpc-statd.service + Before= rpc-statd-notify.service + +diff -up nfs-utils-1.3.0/systemd/rpc-statd-notify.service.orig nfs-utils-1.3.0/systemd/rpc-statd-notify.service +--- nfs-utils-1.3.0/systemd/rpc-statd-notify.service.orig 2015-06-25 15:01:27.658527188 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-statd-notify.service 2015-06-25 15:05:13.667774624 -0400 +@@ -1,7 +1,8 @@ + [Unit] + Description=Notify NFS peers of a restart +-Requires=network-online.target +-After=network-online.target nss-lookup.target ++DefaultDependencies=no ++Requires=network.target ++After=local-fs.target network.target nss-lookup.target + + # Do not start up in HA environments + ConditionPathExists=!/var/lib/nfs/statd/sm.ha +diff -up nfs-utils-1.3.0/systemd/rpc-svcgssd.service.orig nfs-utils-1.3.0/systemd/rpc-svcgssd.service +--- nfs-utils-1.3.0/systemd/rpc-svcgssd.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-svcgssd.service 2015-06-25 15:01:45.166856358 -0400 +@@ -1,7 +1,8 @@ + [Unit] + Description=RPC security service for NFS server ++DefaultDependencies=no + Requires=var-lib-nfs-rpc_pipefs.mount +-After=var-lib-nfs-rpc_pipefs.mount ++After=var-lib-nfs-rpc_pipefs.mount local-fs.target + PartOf=nfs-server.service + PartOf=nfs-utils.service + +diff -up nfs-utils-1.3.0/systemd/rpc-statd.service.orig nfs-utils-1.3.0/systemd/rpc-statd.service +--- nfs-utils-1.3.0/systemd/rpc-statd.service.orig 2014-03-25 11:12:07.000000000 -0400 ++++ nfs-utils-1.3.0/systemd/rpc-statd.service 2015-09-14 11:49:19.547384763 -0400 +@@ -2,8 +2,8 @@ + Description=NFS status monitor for NFSv2/3 locking. + DefaultDependencies=no + Conflicts=umount.target +-Requires=nss-lookup.target rpcbind.target +-After=network.target nss-lookup.target rpcbind.target ++Requires=nss-lookup.target rpcbind.service ++After=network.target nss-lookup.target rpcbind.service + + PartOf=nfs-utils.service + diff --git a/SOURCES/nfs-utils-1.3.0-systemd-rpcpipefs.patch b/SOURCES/nfs-utils-1.3.0-systemd-rpcpipefs.patch new file mode 100644 index 0000000..2e3001b --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-systemd-rpcpipefs.patch @@ -0,0 +1,38 @@ +commit 8b3abe3a0ae941f3f52f99bc44388b7beb3d9bb8 +Author: Colin Walters +Date: Fri Jun 26 09:31:16 2015 -0400 + + systemd: Set var-lib-nfs-rpc_pipefs.mount After= tmpfiles + + OSTree is a mechanism for atomic updates of operating systems, with + designs for how system state is managed; in particular, `/var` should + start out empty, and components are responsible for creating content + there at runtime. + + rpm-ostree consumes RPMs and commits them to an OSTree repository. + It has some support for automatically synthesizing systemd `tmpfiles.d` + snippets from RPM content in `/var` using systemd-tmpfiles. + + However, in this case nfs-utils wants a mount point directory, and + it's running before systemd-tmpfiles. It should be perfectly fine to + do this mount after tmpfiles has run. + + A better fix for this would be to move transient directories to + `/run`; However, that would be an invasive change, which can happen + after this fix. + + Signed-off-by: Colin Walters + Signed-off-by: Steve Dickson + +diff --git a/systemd/var-lib-nfs-rpc_pipefs.mount b/systemd/var-lib-nfs-rpc_pipefs.mount +index 33c5db6..26d1c76 100644 +--- a/systemd/var-lib-nfs-rpc_pipefs.mount ++++ b/systemd/var-lib-nfs-rpc_pipefs.mount +@@ -1,6 +1,7 @@ + [Unit] + Description=RPC Pipe File System + DefaultDependencies=no ++After=systemd-tmpfiles-setup.service + Conflicts=umount.target + + [Mount] diff --git a/SOURCES/nfs-utils-1.3.0-umount-opt-typo.patch b/SOURCES/nfs-utils-1.3.0-umount-opt-typo.patch new file mode 100644 index 0000000..9d65e09 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-umount-opt-typo.patch @@ -0,0 +1,21 @@ +commit a5f1e5797f465d326043eb9daa5f1ad3750d4c9d +Author: Steve Dickson +Date: Tue Jun 7 16:07:27 2016 -0400 + + umount: fixed typo in usage message + + Signed-off-by: Steve Dickson + +diff --git a/utils/mount/utils.c b/utils/mount/utils.c +index 92662ed..865a4a0 100644 +--- a/utils/mount/utils.c ++++ b/utils/mount/utils.c +@@ -110,7 +110,7 @@ void mount_usage(void) + void umount_usage(void) + { + printf(_("usage: %s dir [-fvnrlh]\n"), progname); +- printf(_("options:\n\t-f\t\tforce unmount\n")); ++ printf(_("options:\n\t-f\tforce unmount\n")); + printf(_("\t-v\tverbose\n")); + printf(_("\t-n\tDo not update /etc/mtab\n")); + printf(_("\t-r\tremount\n")); diff --git a/SOURCES/nfs-utils_env.sh b/SOURCES/nfs-utils_env.sh new file mode 100644 index 0000000..246e894 --- /dev/null +++ b/SOURCES/nfs-utils_env.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# +# Extract configuration from /etc/sysconfig/nfs and write +# environment variables to /run/sysconfig/nfs-utils to be +# used by the systemd nfs-config service +# + +nfs_config=/etc/sysconfig/nfs +if test -r $nfs_config; then + . $nfs_config +fi + +if [ -n "$MOUNTD_PORT" ]; then + RPCMOUNTDOPTS="$RPCMOUNTDOPTS -p $MOUNTD_PORT" +fi + +if [ -n "$STATD_PORT" ]; then + STATDARG="$STATDARG -p $STATD_PORT" +fi + +if [ -n "$STATD_OUTGOING_PORT" ]; then + STATDARG="$STATDARG -o $STATD_OUTGOING_PORT" +fi + +if [ -n "$STATD_HA_CALLOUT" ]; then + STATDARG="$STATDARG -H $STATD_HA_CALLOUT" +fi + +if [ -n "$NFSD_V4_GRACE" ]; then + grace="-G $NFSD_V4_GRACE" +fi + +if [ -n "$NFSD_V4_LEASE" ]; then + lease="-L $NFSD_V4_LEASE" +fi + +if [ -n "$RPCNFSDCOUNT" ]; then + nfsds=$RPCNFSDCOUNT +else + nfsds=8 +fi + +if [ -n "$RPCNFSDARGS" ]; then + nfsdargs="$RPCNFSDARGS $grace $lease $nfsds" +else + nfsdargs="$grace $lease $nfsds" +fi + +mkdir -p /run/sysconfig +{ +echo RPCNFSDARGS=\"$nfsdargs\" +echo RPCMOUNTDARGS=\"$RPCMOUNTDOPTS\" +echo STATDARGS=\"$STATDARG\" +echo SMNOTIFYARGS=\"$SMNOTIFYARGS\" +echo RPCIDMAPDARGS=\"$RPCIDMAPDARGS\" +echo GSSDARGS=\"$RPCGSSDARGS\" +echo BLKMAPDARGS=\"$BLKMAPDARGS\" +echo GSS_USE_PROXY=\"$GSS_USE_PROXY\" +} > /run/sysconfig/nfs-utils diff --git a/SOURCES/nfs.sysconfig b/SOURCES/nfs.sysconfig new file mode 100644 index 0000000..7e0c827 --- /dev/null +++ b/SOURCES/nfs.sysconfig @@ -0,0 +1,55 @@ + +# +# +# To set lockd kernel module parameters please see +# /etc/modprobe.d/lockd.conf +# + +# Optional arguments passed to rpc.nfsd. See rpc.nfsd(8) +RPCNFSDARGS="" +# Number of nfs server processes to be started. +# The default is 8. +#RPCNFSDCOUNT=16 +# +# Set V4 grace period in seconds +#NFSD_V4_GRACE=90 +# +# Set V4 lease period in seconds +#NFSD_V4_LEASE=90 +# +# Optional arguments passed to rpc.mountd. See rpc.mountd(8) +RPCMOUNTDOPTS="" +# Port rpc.mountd should listen on. +#MOUNTD_PORT=892 +# +# Optional arguments passed to rpc.statd. See rpc.statd(8) +STATDARG="" +# Port rpc.statd should listen on. +#STATD_PORT=662 +# Outgoing port statd should used. The default is port +# is random +#STATD_OUTGOING_PORT=2020 +# Specify callout program +#STATD_HA_CALLOUT="/usr/local/bin/foo" +# +# +# Optional arguments passed to sm-notify. See sm-notify(8) +SMNOTIFYARGS="" +# +# Optional arguments passed to rpc.idmapd. See rpc.idmapd(8) +RPCIDMAPDARGS="" +# +# Optional arguments passed to rpc.gssd. See rpc.gssd(8) +# Note: The rpc-gssd service will not start unless the +# file /etc/krb5.keytab exists. If an alternate +# keytab is needed, that separate keytab file +# location may be defined in the rpc-gssd.service's +# systemd unit file under the ConditionPathExists +# parameter +RPCGSSDARGS="" +# +# Enable usage of gssproxy. See gssproxy-mech(8). +GSS_USE_PROXY="yes" +# +# Optional arguments passed to blkmapd. See blkmapd(8) +BLKMAPDARGS="" diff --git a/SPECS/nfs-utils.spec b/SPECS/nfs-utils.spec new file mode 100644 index 0000000..8becce8 --- /dev/null +++ b/SPECS/nfs-utils.spec @@ -0,0 +1,2194 @@ +Summary: NFS utilities and supporting clients and daemons for the kernel NFS server +Name: nfs-utils +URL: http://sourceforge.net/projects/nfs +Version: 1.3.0 +Release: 0.48%{?dist}.1 +Epoch: 1 + +# group all 32bit related archs +%define all_32bit_archs i386 i486 i586 i686 athlon ppc sparcv9 + +Source0: https://www.kernel.org/pub/linux/utils/nfs-utils/%{version}/%{name}-%{version}.tar.xz + +Source1: id_resolver.conf +Source2: nfs.sysconfig +Source3: nfs-utils_env.sh +Source4: lockd.conf +Source5: 24-nfs-server.conf + +# +# RHEL7.1 +# +Patch001: nfs-utils-1.3.0-rpcgssd-timeout.patch +Patch002: nfs-utils-1.3.0-statd-callback.patch +Patch003: nfs-utils-1.3.0-mountd-start-statd-path.patch +Patch004: nfs-utils-1.3.0-rpcgssd-noerror-message.patch +Patch005: nfs-utils-1.3.0-rpcgssd-acceptor.patch +Patch006: nfs-utils-1.3.0-exportfs-NULL-pointer-test.patch +Patch007: nfs-utils-1.3.0-rpcgssd-errno-typo.patch +Patch008: nfs-utils-1.3.0-nfsiostat-output.patch +Patch009: nfs-utils-1.3.0-nfsclient-after.patch +Patch010: nfs-utils-1.3.0-startstatd-systemd.patch +Patch011: nfs-utils-1.3.0-gssproxy.patch +Patch012: nfs-utils-1.3.0-systemd-args.patch +Patch013: nfs-utils-1.3.0-libmount-umount-verbose.patch +Patch014: nfs-utils-1.3.0-mountd-dos.patch +Patch015: nfs-utils-1.3.0-exportfs-ipv6-arg.patch +Patch016: nfs-utils-1.3.0-exportfs-noreaddirplus.patch +Patch017: nfs-utils-1.3.0-systemd-idmapd.patch +Patch018: nfs-utils-1.3.0-systemd-ha-nonotify.patch +# +# RHEL7.2 +# +Patch019: nfs-utils-1.3.0-blkmapd-pnfs.patch +Patch020: nfs-utils-1.3.0-mountstats-update.patch +Patch021: nfs-utils-1.3.0-mountd-v4root-sec.patch +Patch022: nfs-utils-1.3.0-systemd-idmapd-varlib.patch +Patch023: nfs-utils-1.3.0-nfsdcltrack-v2schema.patch +Patch024: nfs-utils-1.3.0-mountd-manpage-args.patch +Patch025: nfs-utils-1.3.0-mountd-manpage-netconfig.patch +Patch026: nfs-utils-1.3.0-systemd-rpcbind.patch +Patch027: nfs-utils-1.3.0-blkmapd-loop.patch +Patch028: nfs-utils-1.3.0-gssd-noclear-retval.patch +Patch029: nfs-utils-1.3.0-gssd-tgt-flood.patch +Patch030: nfs-utils-1.3.0-systemd-decouple.patch +# +# RHEL7.3 +# +Patch031: nfs-utils-1.3.0-nfsidmap-timeout.patch +Patch032: nfs-utils-1.3.0-hostpton-eainoname.patch +Patch033: nfs-utils-1.3.0-rpcgssd-maccout-nocase.patch +Patch034: nfs-utils-1.3.0-nfsdcltrack-v2schema-update.patch +Patch035: nfs-utils-1.3.0-mountd-usage-error.patch +Patch036: nfs-utils-1.3.0-mountd-usage.patch +Patch037: nfs-utils-1.3.0-rpcgssd-debug.patch +Patch038: nfs-utils-1.3.0-start-statd-once.patch +Patch039: nfs-utils-1.2.9-exportfs-badentries.patch +Patch040: nfs-utils-1.3.0-mount-remount.patch +Patch041: nfs-utils-1.3.0-nfs_connect_nb-eintr.patch +Patch042: nfs-utils-1.3.0-statd-monlists.patch +Patch043: nfs-utils-1.3.0-nfsidmap-update.patch +Patch044: nfs-utils-1.3.0-mountstats-manpage-fix.patch +Patch045: nfs-utils-1.3.0-systemd-config.patch +Patch046: nfs-utils-1.3.0-exportfs-slashes.patch +Patch047: nfs-utils-1.3.0-exportfs-hostnames.patch +Patch048: nfs-utils-1.3.0-exportfs-bufsiz.patch +Patch049: nfs-utils-1.3.0-blkmapd-usage.patch +Patch050: nfs-utils-1.3.0-rpcidmapd-usage.patch +Patch051: nfs-utils-1.3.0-rpcgssd-multithread.patch +Patch052: nfs-utils-1.3.0-rpcgssd-findkeytab.patch +Patch053: nfs-utils-1.3.0-start-statd-root.patch +Patch054: nfs-utils-1.3.0-nfsd-rdma.patch +Patch055: nfs-utils-1.3.0-nfsd-warnings.patch +Patch056: nfs-utils-1.3.0-mountd-manpage-P.patch +Patch057: nfs-utils-1.3.0-mountstats-manpage-fix2.patch +Patch058: nfs-utils-1.3.0-mountd-netgroups.patch +Patch059: nfs-utils-1.3.0-umount-opt-typo.patch +Patch060: nfs-utils-1.3.0-mount-usage.patch +Patch061: nfs-utils-1.3.0-nfsidmap-h-opt.patch +Patch062: nfs-utils-1.3.0-exportfs-empty-exports.patch +Patch063: nfs-utils-1.3.0-statd-warnings.patch +Patch064: nfs-utils-1.3.0-start-statd-flock.patch +Patch065: nfs-utils-1.3.0-mountd-root.patch +Patch066: nfs-utils-1.3.0-mount-nfs-types.patch +# +# RHEL7.4 +# +Patch067: nfs-utils-1.3.0-mount-default-v42.patch +Patch068: nfs-utils-1.3.0-gssd-default-tcp.patch +Patch069: nfs-utils-1.3.0-mountstats-pnfs.patch +Patch070: nfs-utils-1.3.0-nfsdcltrack-usage.patch +Patch071: nfs-utils-1.3.0-daemon_init-warning.patch +Patch072: nfs-utils-1.3.0-mount-v4arg-fix.patch +Patch073: nfs-utils-1.3.0-systemd-rpcpipefs.patch +Patch074: nfs-utils-1.3.0-mountd-filedes.patch +Patch075: nfs-utils-1.3.0-exportfs-redundant.patch +Patch076: nfs-utils-1.3.0-nfs-conf.patch +Patch077: nfs-utils-1.3.0-gssd-rdma-to-tcp.patch +Patch078: nfs-utils-1.3.0-gssd-thread-safe.patch +Patch079: nfs-utils-1.3.0-mount-uninit-structs.patch +Patch080: nfs-utils-1.3.0-exportfs-securitylabel.patch +Patch081: nfs-utils-1.3.0-mount-v41.patch +Patch082: nfs-utils-1.3.0-nfsstat-retval.patch +Patch083: nfs-utils-1.3.0-server-generator.patch +Patch084: nfs-utils-1.3.0-nfsman-minorversion.patch +Patch085: nfs-utils-1.3.0-rpcgssd-preferred-realm.patch +Patch086: nfs-utils-1.3.0-mountstats-iostats.patch +Patch087: nfs-utils-1.3.0-mount-prognotreg.patch +Patch088: nfs-utils-1.3.0-statd-notify-grace-period.patch +Patch089: nfs-utils-1.3.0-nfsstat-mounts.patch +Patch090: nfs-utils-1.3.0-nfsd-man-correction.patch +Patch091: nfs-utils-1.3.0-nfsdcltrack-errors.patch +Patch092: nfs-utils-1.3.0-systemd-network-online.patch +Patch093: nfs-utils-1.3.0-mount-explicit-rback.patch +Patch094: nfs-utils-1.3.0-systemd-gssproxy.patch +Patch095: nfs-utils-1.3.0-mount-use-minor-default.patch +Patch096: nfs-utils-1.3.0-mount-restore-econn.patch +Patch097: nfs-utils-1.3.0-exportfs-path-comp.patch +# +# RHEL7.4-Z +# +Patch098: nfs-utils-1.3.0-mount-addressfailed.patch +Patch099: nfs-utils-1.3.0-mount-eacces.patch + +Patch100: nfs-utils-1.2.1-statdpath-man.patch +Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch +Patch102: nfs-utils-1.2.3-sm-notify-res_init.patch +Patch103: nfs-utils-1.2.5-idmap-errmsg.patch + +Group: System Environment/Daemons +Provides: exportfs = %{epoch}:%{version}-%{release} +Provides: nfsstat = %{epoch}:%{version}-%{release} +Provides: showmount = %{epoch}:%{version}-%{release} +Provides: rpcdebug = %{epoch}:%{version}-%{release} +Provides: rpc.idmapd = %{epoch}:%{version}-%{release} +Provides: rpc.mountd = %{epoch}:%{version}-%{release} +Provides: rpc.nfsd = %{epoch}:%{version}-%{release} +Provides: rpc.statd = %{epoch}:%{version}-%{release} +Provides: rpc.gssd = %{epoch}:%{version}-%{release} +Provides: mount.nfs = %{epoch}:%{version}-%{release} +Provides: mount.nfs4 = %{epoch}:%{version}-%{release} +Provides: umount.nfs = %{epoch}:%{version}-%{release} +Provides: umount.nfs4 = %{epoch}:%{version}-%{release} +Provides: sm-notify = %{epoch}:%{version}-%{release} +Provides: start-statd = %{epoch}:%{version}-%{release} + +License: MIT and GPLv2 and GPLv2+ and BSD +Requires: rpcbind, sed, gawk, sh-utils, fileutils, textutils, grep +Requires: kmod, keyutils, quota +BuildRequires: libevent-devel libcap-devel +BuildRequires: libnfsidmap-devel libtirpc-devel >= 0.2.4-0.7 libblkid-devel +BuildRequires: krb5-libs >= 1.4 autoconf >= 2.57 openldap-devel >= 2.2 +BuildRequires: automake, libtool, glibc-headers, device-mapper-devel +BuildRequires: krb5-devel, tcp_wrappers-devel, libmount-devel +BuildRequires: fedfs-utils-devel >= 0.8.0-7, sqlite-devel +Requires(pre): shadow-utils >= 4.0.3-25 +Requires(pre): /sbin/chkconfig /sbin/nologin +Requires: libnfsidmap libevent +Requires: libtirpc >= 0.2.4-0.7 libblkid libcap libmount +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units + +Requires: gssproxy >= 0.7.0-3 +Conflicts: gssproxy < 0.3.0-10 + +%description +The nfs-utils package provides a daemon for the kernel NFS server and +related tools, which provides a much higher level of performance than the +traditional Linux NFS server used by most users. + +This package also contains the showmount program. Showmount queries the +mount daemon on a remote host for information about the NFS (Network File +System) server on the remote host. For example, showmount can display the +clients which are mounted on that host. + +This package also contains the mount.nfs and umount.nfs program. + +%prep +%setup -q + +# 1009528 - have a configurable connection timeout for the rpcgssd service +%patch001 -p1 +# 1108105 - "Adding callback on sm_notify" into nfs-utils on RHEL7 +%patch002 -p1 +# 1116794 - wrong PATH in /usr/sbin/start-statd +%patch003 -p1 +# 1117384 - rpc.gssd always start fail, and no enough log/message to user +%patch004 -p1 +# 1088011 - kerberized NFSv4.0 backchannel requests aren't authenticated properly by client +%patch005 -p1 +# 1083018 - code defect support/export/hostname.c: host_pton() NULL pointer... +%patch006 -p1 +# 1082480 - [gssd] code defects in get_servername().... +%patch007 -p1 +# 1109864 - Man pages are not explaining the output of nfsiostat +%patch008 -p1 +# 1144440 - Upgrade to latest upstream systemd scripts +%patch009 -p1 +%patch010 -p1 +# 1082746 - remove support for rpc.svcgssd +%patch011 -p1 +# 170364 - Typos in nfs-utils sysconfig files and associated script +%patch012 -p1 +# 923582 - umount -vvv not working +%patch013 -p1 +# 1163891 - rpc.mountd can be blocked by a bad client +%patch014 -p1 +# 1161490 - [exportfs] when export [$IPv6]:$expdir always random fail +%patch015 -p1 +# 1161458 - nfs-utils patch for Readdirplus / disable readdirplus +%patch016 -p1 +# 1159234 - ocf:heartbeat:nfsserver does not umount /var/lib/nfs on shared disk +%patch017 -p1 +# 1182692 - disable sm-notify on 'systemctl start nfs-server' no longer works +%patch018 -p1 +# 1214821 - nfs-utils updates for block pnfs +%patch019 -p1 +# 1215808 - Update mountstats command to the latest upstream version +%patch020 -p1 +# 1187223 - rpc.mountd can set up pseudo exports without... +%patch021 -p1 +# 1164064 - RHEL-7.1 regression fail: service nfs-idmapd start fail +%patch022 -p1 +# 1234598 - Early grace period expiry with NFSv4.1 +%patch023 -p1 +# 1003558 - In rpc.mountd man page -V -f -p -H and so on need and args +%patch024 -p1 +# 1196646 - man pages nfs/mount.fs should mention /etc/nfsmount.conf ... +%patch025 -p1 +# 1171603 - Require rpcbind.service in nfs-server.service rather than ... +%patch026 -p1 +# 237301 - blkmapd: Fix infinite loop when reading serial +%patch027 -p1 +# 1087350 - [gssd] code defects in gssd_search_krb5_keytab()... +%patch028 -p1 +# 1264999 - rpc.gssd fetches a TGT on every machine credential upcall +%patch029 -p1 +# 1266993 - restarting rpbind also restart the the nfs server +%patch030 -p1 +# 1161222 - nfsidmap not setting key timeouts +%patch031 -p1 +# 1276099 - exportfs -u incorrectly exits with a 1 whenever... +%patch032 -p1 +# 1268040 - rpc.gssd should not assume that the machine account is in uppercase +%patch033 -p1 +# 1285097 - updated nfs-utils package broke nfsdcltrack +%patch034 -p1 +# 1003539 - If rpc.mountd specify options: "-N 2 -N 3 -N 4", should output... +%patch035 -p1 +# 1003716 - rpc.mountd -h: 1. In help info not include -r|--reverse-lookup... +%patch036 -p1 +# 1273163 - Allow gssd and svcgssd to set the libtirpc debug level +%patch037 -p1 +# 1300007 - start-statd: don't run multiple rpc.statds on the one host. +%patch038 -p1 +# 1287468 - Unable to start nfs server.service if any of the client is down... +%patch039 -p1 +# 1313550 - Nondeterministic DNS lookups cause NFS kdump targets to fail +%patch040 -p1 +# 1299003 - Unhandled EINTR during connection establishment leads... +%patch041 -p1 +# 1284576 - lockd's and statd's monitor lists get out of sync +%patch042 -p1 +# 1290488 Request a method(like a testperm) to show parameters of idmapd.conf +%patch043 -p1 +# 1266013 - need to remove a few bogus .R macros of mountstats man page +%patch044 -p1 +# 1331460 - nfs-config service is *not* being re-run as needed +%patch045 -p1 +# 1276534 - exportfs -u cannot unexport when the specified... +%patch046 -p1 +# 1331801 - exportfs -u can exit with status 1 if there are multiple... +%patch047 -p1 +# 1243234 - exportfs: code defect, when export path length > 986... +%patch048 -p1 +# 1001431 - RFE: feature blkmapd add help -h option, to output "usage:" info +%patch049 -p1 +# 1001438 - RFE: feature rpc.idmapd add help -h option, to output "usage:" info +%patch050 -p1 +# 1331540 - multi-threaded rpc.gssd +%patch051 -p1 +# 1334848 - cthon - rpc.gssd crash reading krb5.keytab in find_keytab_entry() +%patch052 -p1 +# 1275082 - [vdsm] NFS mount fails sometimes with "rpc.statd is not running... +%patch053 -p1 +# 1310691 - "--rdma" option of rpc.nfsd enables the wrong port +%patch054 -p1 +# 1336419 - nfsd: Remove some warnings nfsd.c +%patch055 -p1 +# 1037924 - [rpc.mountd] update rpc.mountd(8) manpage to change -P... +%patch056 -p1 +# 1263966 - typo in mountstats man page that should not contain "-s|--since" +%patch057 -p1 +# 1341908 - rpc.mountd does not check for membership of IP... +%patch058 -p1 +# 1246329 - umount.nfs -h/--help output typo with -f force unmount +%patch059 -p1 +# 1001443 - if no args specified, mount.nfs can not output the usage info +%patch060 -p1 +# 1339877 - nfsidmap add help -h option to output usage info +%patch061 -p1 +# 1340788 - [exportfs] should not fail on empty exports file with... +%patch062 -p1 +# 1347030 - rpc.statd emits warnings like "Failed to delete:.... +%patch063 -p1 +# 1300007 - start-statd: don't run multiple rpc.statds on the one host. (v2) +%patch064 -p1 +# 1353680 - NFSv4 export of "/" doesn't respect "crossmnt" export option +%patch065 -p1 +# 1363737 - man mount.nfs incorrectly mentions the default mount.... +%patch066 -p1 +# 1375259 - NFSv4.2 as default NFS mount protocol +%patch067 -p1 +# 1386759 - nfs-utils requires a fix to support NFS/RDMA mounts.... +%patch068 -p1 +# 1377740 - Add pNFS READs and WRITEs to the mountstats program output +%patch069 -p1 +# 1001494 - RFE: feature, add "[Uu]sage:" string in the nfsdcltrack -h output info +%patch070 -p1 +# 1377914 - Compiler Warning of support/nfs/mydaemon.c.... +%patch071 -p1 +# 1404617 - mount.nfs fall back to version 3 when specifying... +%patch072 -p1 +# 1406164 - var-lib-nfs-rpc_pipefs.mount fails +%patch073 -p1 +# 1409903 - Occasional SELinux denials when starting up knfsd +%patch074 -p1 +# 1396402 - [exportfs] exportfs -s output some exports options twice, but.. +%patch075 -p1 +# 1418041 - Update nfs-utils to use latest upstream configuration style +%patch076 -p1 +# 1386759 - nfs-utils requires a fix to support NFS/RDMA mounts.... +%patch077 -p1 +# 1419280 - Non-thread-safe functions used in multi-threaded rpc.gssd +%patch078 -p1 +# 1415024 - [uninitialized struct] get wrong nfs version when doing nfs mount +%patch079 -p1 +# 1435899 - exportfs: support "security_label" export option +%patch080 -p1 +# 1435901 - mount.nfs: starts mount negation with v4.2 it should be v4.1 +%patch081 -p1 +# 1400658 - nfsstat -m command returns false return code +%patch082 -p1 +# 1437190 - nfs-server-generator: handle 'noauto' mounts correctly. +%patch083 -p1 +# 1389827 - "minorversion=" mount option missing in nfs(5) man page +%patch084 -p1 +# 1432643 - segfault in rpc.gssd in find_keytab_entry +%patch085 -p1 +# 1400106 - mountstats: handle KeyError in accumulate_iostats +%patch086 -p1 +# 1404121 - NFS fails to mount on boot if both client and server.... +%patch087 -p1 +# 1424599 - sm-notify ending grace period early can inhibit... +%patch088 -p1 +# 1425956 - nfsstat --mounts is unrecognized option +%patch089 -p1 +# 1432750 - Manual page bug: two inaccuracies in nfsd(7) +%patch090 -p1 +# 1443176 - nfsdcltrack: Unable to prepare select statement... +%patch091 -p1 +# 1409012 - nfs-server runs before network is ready... +%patch092 -p1 +# 1447849 - mount.nfs4 falls back to version 3 when mounting... +%patch093 -p1 +# 1459483 - nfs-utils need to cause gssproxy reload +%patch094 -p1 +# 1458504 mount.nfs: NFSv4 specified mount need to start negotiation... +%patch095 -p1 +# 1404121 - NFS fails to mount on boot if both client and.... +%patch096 -p1 +# 1389046 Pacemaker node fenced out due to redundant export... +%patch097 -p1 +# 1498959 - RHEL7.4: service nfs-server start fails the first time... +%patch098 -p1 +# 1518718 - RHEL7.4: NFS mount to DELL/EMC Isilon servers fails... +%patch099 -p1 + +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 + +# Remove .orig files +find . -name "*.orig" | xargs rm -f + +%build + +%ifarch s390 s390x sparcv9 sparc64 +PIE="-fPIE" +%else +PIE="-fpie" +%endif +export PIE + +RELRO="-Wl,-z,relro,-z,now" + +sh -x autogen.sh + +CFLAGS="`echo $RPM_OPT_FLAGS $ARCH_OPT_FLAGS $PIE $RELRO -D_FILE_OFFSET_BITS=64`" +%configure \ + CFLAGS="$CFLAGS" \ + CPPFLAGS="$DEFINES" \ + LDFLAGS="-pie" \ + --enable-mountconfig \ + --enable-ipv6 \ + --with-statdpath=/var/lib/nfs/statd \ + --enable-libmount-mount \ + --with-systemd + +make %{?_smp_mflags} all + +%install +rm -rf $RPM_BUILD_ROOT/* + +mkdir -p $RPM_BUILD_ROOT%/sbin +mkdir -p $RPM_BUILD_ROOT%{_sbindir} +mkdir -p $RPM_BUILD_ROOT%{_unitdir} +mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8 +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/request-key.d +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/modprobe.d +make DESTDIR=$RPM_BUILD_ROOT install +install -s -m 755 tools/rpcdebug/rpcdebug $RPM_BUILD_ROOT%{_sbindir} +install -m 644 utils/mount/nfsmount.conf $RPM_BUILD_ROOT%{_sysconfdir} +install -m 644 nfs.conf $RPM_BUILD_ROOT%{_sysconfdir} +install -m 644 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/request-key.d +install -m 644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/nfs + +# +# Don't install code that is no longer supported +# +rm systemd/rpc-svcgssd.service +rm $RPM_BUILD_ROOT%{_sbindir}/rpc.svcgssd +rm $RPM_BUILD_ROOT%{_mandir}/man8/rpc.svcgssd.8 +rm $RPM_BUILD_ROOT%{_mandir}/man8/svcgssd.8 + +mkdir -p $RPM_BUILD_ROOT/run/sysconfig +mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/scripts +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/gssproxy +install -m 755 %{SOURCE3} $RPM_BUILD_ROOT/usr/lib/systemd/scripts/nfs-utils_env.sh +install -m 644 %{SOURCE4} $RPM_BUILD_ROOT%{_sysconfdir}/modprobe.d/lockd.conf +install -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{_sysconfdir}/gssproxy + +# +# For backwards compatablity +# +cd $RPM_BUILD_ROOT%{_unitdir} +ln -s nfs-server.service nfs.service +ln -s rpc-gssd.service nfs-secure.service +ln -s rpc-gssd.service rpcgssd.service +ln -s nfs-idmapd.service nfs-idmap.service +ln -s nfs-idmapd.service rpcidmapd.service +ln -s rpc-statd.service nfs-lock.service +ln -s rpc-statd.service nfslock.service + + +mkdir -p $RPM_BUILD_ROOT%{_sharedstatedir}/nfs/rpc_pipefs + +touch $RPM_BUILD_ROOT%{_sharedstatedir}/nfs/rmtab +mv $RPM_BUILD_ROOT%{_sbindir}/rpc.statd $RPM_BUILD_ROOT/sbin + +mkdir -p $RPM_BUILD_ROOT%{_sharedstatedir}/nfs/statd/sm +mkdir -p $RPM_BUILD_ROOT%{_sharedstatedir}/nfs/statd/sm.bak +mkdir -p $RPM_BUILD_ROOT%{_sharedstatedir}/nfs/v4recovery +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/exports.d + +%clean +rm -rf $RPM_BUILD_ROOT/* + +%pre +# move files so the running service will have this applied as well +for x in gssd idmapd ; do + if [ -f /var/lock/subsys/rpc.$x ]; then + mv /var/lock/subsys/rpc.$x /var/lock/subsys/rpc$x + fi +done + +%define rpcuser_uid 29 +# Create rpcuser gid as long as it does not already exist +cat /etc/group | cut -d':' -f 1 | grep --quiet rpcuser 2>/dev/null +if [ "$?" -eq 1 ]; then + /usr/sbin/groupadd -g %{rpcuser_uid} rpcuser >/dev/null 2>&1 || : +else + /usr/sbin/groupmod -g %{rpcuser_uid} rpcuser >/dev/null 2>&1 || : +fi + +# Create rpcuser uid as long as it does not already exist. +cat /etc/passwd | cut -d':' -f 1 | grep --quiet rpcuser 2>/dev/null +if [ "$?" -eq 1 ]; then + /usr/sbin/useradd -l -c "RPC Service User" -r -g %{rpcuser_uid} \ + -s /sbin/nologin -u %{rpcuser_uid} -d /var/lib/nfs rpcuser >/dev/null 2>&1 || : +else + /usr/sbin/usermod -u %{rpcuser_uid} -g %{rpcuser_uid} rpcuser >/dev/null 2>&1 || : +fi + +# Using the 16-bit value of -2 for the nfsnobody uid and gid +%define nfsnobody_uid 65534 + +# Create nfsnobody gid as long as it does not already exist +cat /etc/group | cut -d':' -f 1 | grep --quiet nfsnobody 2>/dev/null +if [ "$?" -eq 1 ]; then + /usr/sbin/groupadd -g %{nfsnobody_uid} nfsnobody >/dev/null 2>&1 || : +else + /usr/sbin/groupmod -g %{nfsnobody_uid} nfsnobody >/dev/null 2>&1 || : +fi + +# Create nfsnobody uid as long as it does not already exist. +cat /etc/passwd | cut -d':' -f 1 | grep --quiet nfsnobody 2>/dev/null +if [ "$?" -eq 1 ]; then + /usr/sbin/useradd -l -c "Anonymous NFS User" -r -g %{nfsnobody_uid} \ + -s /sbin/nologin -u %{nfsnobody_uid} -d /var/lib/nfs nfsnobody >/dev/null 2>&1 || : +else + + /usr/sbin/usermod -u %{nfsnobody_uid} -g %{nfsnobody_uid} nfsnobody >/dev/null 2>&1 || : +fi + +%post +if [ $1 -eq 1 ] ; then + # Initial installation + /bin/systemctl enable nfs-client.target >/dev/null 2>&1 || : + /bin/systemctl restart nfs-config >/dev/null 2>&1 || : +fi +%systemd_post nfs-config +%systemd_post nfs-server + +# Make sure statd used the correct uid/gid. +chown -R rpcuser:rpcuser /var/lib/nfs/statd + +%preun +if [ $1 -eq 0 ]; then + %systemd_preun nfs-client.target + %systemd_preun nfs-server.server + + /usr/sbin/userdel rpcuser 2>/dev/null || : + /usr/sbin/groupdel rpcuser 2>/dev/null || : + /usr/sbin/userdel nfsnobody 2>/dev/null || : + /usr/sbin/groupdel nfsnobody 2>/dev/null || : + rm -rf /var/lib/nfs/statd + rm -rf /var/lib/nfs/v4recovery +fi + +%postun +if [ ! -f /etc/sysconfig/nfs-utils-disable-postun ]; then + %systemd_postun_with_restart nfs-client.target + %systemd_postun_with_restart nfs-server + /bin/systemctl --system daemon-reload >/dev/null 2>&1 || : +fi + +%posttrans +# clean up cruft left over by upgrade from versions < 1.3.0-0.8.el7 +if [ -h /etc/systemd/system/multi-user.target.wants/nfs.target ]; then + tgt=$(readlink /etc/systemd/system/multi-user.target.wants/nfs.target) + if [ ! -e $tgt ]; then + /bin/systemctl --quiet is-enabled nfs-server &>/dev/null + reenable=$? + rm -rf /etc/systemd/system/multi-user.target.wants/nfs.target &>/dev/null + rm -rf /etc/systemd/system/nfs.target.wants &>/dev/null + if [ $reenable ]; then + /bin/systemctl --quiet reenable nfs-server &>/dev/null || : + fi + fi +fi + +%triggerun -- nfs-utils < 1:1.2.9-0.5 +/bin/systemctl stop nfs-secure.service >/dev/null 2>&1 || : +/bin/systemctl disable nfs-secure.service >/dev/null 2>&1 || : + +%triggerun -- nfs-utils < 1:1.2.4-2 +/bin/systemctl enable nfs-lock.service >/dev/null 2>&1 || : + +%triggerin -- nfs-utils > 1:1.3.0-0.39 +# reset configuration files and running daemons +if [ $1 -eq 2 ] ; then + /bin/systemctl enable nfs-client.target >/dev/null 2>&1 || : + /bin/systemctl restart nfs-config >/dev/null 2>&1 || : + /bin/systemctl reload-or-try-restart gssproxy >/dev/null 2>&1 || : +fi + +%files +%defattr(-,root,root,-) +%config(noreplace) /etc/sysconfig/nfs +%config(noreplace) /etc/nfsmount.conf +%config(noreplace) /etc/nfs.conf +%dir %{_sysconfdir}/exports.d +%dir %{_sharedstatedir}/nfs/v4recovery +%dir %attr(555,root,root) %{_sharedstatedir}/nfs/rpc_pipefs +%dir %{_sharedstatedir}/nfs +%dir %attr(700,rpcuser,rpcuser) %{_sharedstatedir}/nfs/statd +%dir %attr(700,rpcuser,rpcuser) %{_sharedstatedir}/nfs/statd/sm +%dir %attr(700,rpcuser,rpcuser) %{_sharedstatedir}/nfs/statd/sm.bak +%config(noreplace) %attr(644,rpcuser,rpcuser) %{_sharedstatedir}/nfs/state +%config(noreplace) %verify(not md5 size mtime) %{_sharedstatedir}/nfs/xtab +%config(noreplace) %verify(not md5 size mtime) %{_sharedstatedir}/nfs/etab +%config(noreplace) %verify(not md5 size mtime) %{_sharedstatedir}/nfs/rmtab +%config(noreplace) %{_sysconfdir}/request-key.d/id_resolver.conf +%config(noreplace) %{_sysconfdir}/modprobe.d/lockd.conf +%attr(0600,root,root) %config(noreplace) /%{_sysconfdir}/gssproxy/24-nfs-server.conf +%doc linux-nfs/ChangeLog linux-nfs/KNOWNBUGS linux-nfs/NEW linux-nfs/README +%doc linux-nfs/THANKS linux-nfs/TODO +/sbin/rpc.statd +/sbin/osd_login +%{_sbindir}/exportfs +%{_sbindir}/nfsstat +%{_sbindir}/rpcdebug +%{_sbindir}/rpc.mountd +%{_sbindir}/rpc.nfsd +%{_sbindir}/showmount +%{_sbindir}/rpc.idmapd +%{_sbindir}/rpc.gssd +%{_sbindir}/sm-notify +%{_sbindir}/start-statd +%{_sbindir}/mountstats +%{_sbindir}/nfsiostat +%{_sbindir}/nfsidmap +%{_sbindir}/blkmapd +%{_sbindir}/nfsdcltrack +%{_mandir}/*/* +%{_unitdir}/* +%attr(755,root,root) /usr/lib/systemd/scripts/nfs-utils_env.sh +%{_prefix}/lib/systemd/system-generators/nfs-server-generator + +%attr(4755,root,root) /sbin/mount.nfs +/sbin/mount.nfs4 +/sbin/umount.nfs +/sbin/umount.nfs4 + +%changelog +* Thu Nov 30 2017 Steve Dickson 1.3.0-0.48_4.1 +- mount: handle EACCES during version negotiation (bz 1518718) + +* Fri Oct 6 2017 Steve Dickson 1.3.0-0.48_4 +- rpc.nfsd: Do not fail when all address families are not support (bz 1450528) + +* Mon Jun 19 2017 Steve Dickson 1.3.0-0.48 +- exportfs: fix path comparison in unexportfs_parsed() (bz 1389046) +- Correctly set the minor version when set in nfsmount.conf (1458504) + +* Wed Jun 14 2017 Steve Dickson 1.3.0-0.47 +- mount.nfs: Restore errno after v3 mounts on ECONNREFUSED errors (bz 1404121) + +* Mon Jun 12 2017 Steve Dickson 1.3.0-0.46 +- Use v4 minor default on all v4 mount types (bz 1458504) + +* Wed Jun 7 2017 Steve Dickson 1.3.0-0.45 +- Restart gssproxy when the server is reloaded (bz 1459483) + +* Thu Jun 1 2017 Steve Dickson 1.3.0-0.44 +- Updated patch for bz 1447849 with the upstream version (bz 1447849) + +* Mon May 22 2017 Steve Dickson 1.3.0-0.43 +- mount: explicit v4 mounts should not roll back to v3 (bz 1447849) +- spec: Use reload-or-try-restart to restart gssproxy (bz 1440887) + +* Tue May 9 2017 Steve Dickson 1.3.0-0.42 +- Removed RPCSVCGSSDARGS nfs.sysconfig (bz 1431218) + +* Thu Apr 27 2017 Steve Dickson 1.3.0-0.41 +- nfsdcltrack: silence some expected errors (bz 1443176) +- Conditionally restart gssproxy now that config file is installed (bz 1440887) +- systemd: NFS server services should use network-online (bz 1409012) +- Cleaned up some fuzzy patches (bz 1409012) + +* Sat Apr 8 2017 Steve Dickson 1.3.0-0.40 +- gssd: ensure that preferred_realm is non-NULL (bz 1432643) +- mountstats: handle KeyError in accumulate_iostats() (bz 1400106) +- mount: RPC_PROGNOTREGISTERED should not be a permanent error (bz 1404121) +- sm-notify: ending the grace period early should be configurable (bz 1424599) +- Fixed a couple typos that effected the '--mounts' nfsstat option (bz 1425956) +- Manual page bug: two inaccuracies in nfsd(7) (bz 1432750) + +* Fri Mar 31 2017 Steve Dickson 1.3.0-0.39 +- nfsstats: fix some exit codes (bz 1400658) +- Added server-generator to improve ordering (bz 1437190) +- nfsman: document minorversion (bz 1389827) + +* Tue Mar 28 2017 Steve Dickson 1.3.0-0.38 +- spec.conf: Added gssproxy server config file (bz 1431273) + +* Tue Mar 28 2017 Steve Dickson 1.3.0-0.37 +- exportfs: support "security_label" export option (bz 1435899) +- svcgssd: Don't install code that is not suppported (bz 1431218) +- mount.nfs: start protocol negation with v4.1 instead of v4.2 (bz 1435901) +- nfs.conf: update nfs-conf.patch to include nfs.systemd.man (bz 1418041) + +* Tue Feb 28 2017 Steve Dickson 1.3.0-0.36 +- exportfs: remove redundant exports options output (bz 1396402) +- Add /etc/nfs.conf support (bz 1418041) +- gssd: Convert 'rdma' to 'tcp' protocol (bz 1386759) +- gssd: replace non-thread-safe strtok with strsep (bz 1419280) +- mount: fix mount fail that caused by uninitialized struct (bz 1415024) + +* Fri Jan 6 2017 Steve Dickson 1.3.0-0.35 +- Fixed -o v4 from falling back to v3 (bz 1404617) +- systemd: Set var-lib-nfs-rpc_pipefs.mount After= tmpfiles (bz 1406164) +- mountd: talk to kernel using file descriptors instead of FILE (bz 1409903) + +* Wed Dec 7 2016 Steve Dickson 1.3.0-0.34 +- mount.nfs: Start the mount negation with v4.2 (bz 1375259) +- gssd: Make TCP the default protocol for GSSD connections (bz 1386759) +- mountstats: add pNFS READs and WRITEs (bz 1377740) +- nfsdcltrack: Fixed typo in usage string (bz 1001494) +- mydaemon.c: Removed a warning (bz 1377914) + +* Wed Aug 17 2016 Scott Mayhew 1.3.0-0.33 +- spec: clean up cruft left over by upgrade from older versions (bz 1203765) + +* Thu Aug 4 2016 Steve Dickson 1.3.0-0.32 +- mount.nfs.man, nfs.man: Update distinction between fstypes (bz 1363737) + +* Mon Jul 11 2016 Steve Dickson 1.3.0-0.31 +- mountd: fix next_mnt handling for "/" (bz 1353680) + +* Thu Jun 23 2016 Steve Dickson 1.3.0-0.30 +- statd: suppress a benign log message in nsm_delete_host() (bz 1347030) +- start-statd: Use flock to serialize the running of this script (bz 1300007) +- spec: update requires version of libtirpc-devel (bz 1346711) + +* Thu Jun 9 2016 Steve Dickson 1.3.0-0.29 +- mountd: fix netgroup lookup for resolvable IP addresses (bz 1341908) +- umount: fixed typo in usage message (bz 1246329) +- mount.nfs: added usage output when no arguemnts are given (bz 1001443) +- nfsidmap: added the -h option (bz 1339877) +- exportfs: Do not fail on empty exports file (bz 1340788) + +* Tue Jun 7 2016 Steve Dickson 1.3.0-0.28 +- Added max/min to nlm_timeout comment in lockd.conf (bz 1264387) + +* Fri May 20 2016 Steve Dickson 1.3.0-0.27 +- nfsd: use correct byte order on rdma port (bz 1310691) +- blkmapd: Add the -h flag on the man page (bz 1001431) +- nfsd: Remove some warnings nfsd.c (bz 1336419) +- mountd.man: Update to change -P option as an alias for -p (bz 1037924) +- mountd: cleaned up usage message (bz 1003716) +- mountstats.man: fixed typo in man page (bz 1263966) + +* Mon May 16 2016 Steve Dickson 1.3.0-0.26 +- gssd: use pthreads to handle upcalls (bz 1331540) +- gssd: Fix inner-loop variable reuse (bz 1334848) +- mount: run START_STATD fully as root (bz 1275082) +- lockd: added lockd.conf to set module parameters (bz 1264387) + +* Tue May 3 2016 Steve Dickson 1.3.0-0.25 +- mountstats.man: Remove a few bogus .R macros (bz 1266013) +- systemd: ensure nfs-config service is re-run as needed (bz 1331460) +- exportfs: Deal with path's trailing "/" (bz 1276534) +- exportfs: replace one xlog(D_GENERAL) in host_canonname() (bz 1331801) +- exportfs: Fix buf size in test_export() dump() (bz 1243234) +- blkmapd: Added a usage routine (bz 1001431) +- rpc.idmapd: Added a usage routine (bz 1001438) + +* Thu Apr 28 2016 Steve Dickson 1.3.0-0.24 +- rpcgssd: added upstream debugging support (bz 1273163) +- start-statd: start rpc.statd only once (bz 1300007) +- exportfs: Don't stop the server from coming up when exportfs fails (bz 1287468) +- Changed install permissions on /var/lib/nfs/rpc_pipefs (bz 1291514) +- nfs.sysconfig: added note about the default keytab needing to exist (bz 1292607) +- mount.nfs: skip server address resolution on remount (bz 1313550) +- nfs_connect_nb: handle EINTR during connection establishment (bz 1299003) +- statd: Update existing record if we rece SM_MON with new cookie (bz 1284576) +- nfsidmap: updated to add in two new features (bz 1290488) + +* Thu Feb 11 2016 Steve Dickson 1.3.0-0.23 +- Update to nfsdcltrack v2 schema (bz 1285097) +- mountd: print an error message when no versions are specified (bz 1003539) +- mountd: added missing arugment to usage string (bz 1003716) + +* Thu Dec 3 2015 Steve Dickson 1.3.0-0.22 +- nfsidmap: Correct a failure to set key timeout values (bz 1161222) +- exportfs: Restore the EAI_NONAME check in host_pton() (bz 1276099) +- gssd: Don't assume the machine account will be in uppercase (bz 1268040) + +* Tue Sep 29 2015 Steve Dickson 1.3.0-0.21 +- Stop gssd from flooding the KDC with TGT fetches (bz 1264999) +- Decouple the start/stop of rpcbind with nfs-server and rpc-statd (bz 1266993) + +* Mon Sep 14 2015 Steve Dickson 1.3.0-0.20 +- Added back MOUNT_PORT (bz 1208488) +- rpc-statd now Requires rpcbind.service (bz 1171603) + +* Thu Sep 3 2015 Steve Dickson 1.3.0-0.19 +- Removed the patch for bz1256469 (bz 1259771) + +* Thu Aug 27 2015 Steve Dickson 1.3.0-0.18 +- Stop gssd from silenty reaps cache (bz 1256469) +- Remove errant echo call from spec file (bz 1257144) +- Add more symlinks to make systemd scripts backwards compatible (bz 1159183) + +* Fri Jul 31 2015 Steve Dickson 1.3.0-0.17 +- Fixed return value being overrun in gssd (bz 1087350) + +* Thu Jul 30 2015 Steve Dickson 1.3.0-0.16 +- Updated the mountstats-update.patch to include doc changes (bz 1215808) + +* Thu Jul 23 2015 Steve Dickson 1.3.0-0.15 +- Make sure nfs-client target is enabled (bz 1245804) + +* Tue Jul 14 2015 Steve Dickson 1.3.0-0.14 +- Fixed typeo in rpc.mount man page (bz 1003558) + +* Wed Jul 1 2015 Steve Dickson 1.3.0-0.13 +- Fix infinite loop in blkmapd (bz 1237301) + +* Wed Jun 24 2015 Steve Dickson 1.3.0-0.12 +- Fixed nfs-idmap start race (bz 1164064) +- Updated nfsdcltrack v2 schema (bz 1234598) +- Added missing arguments in rpc.mountd man page (bz 1003558) +- Added nfsconfig.conf to nfs.man and mount.nfs.man (bz 1196646) +- nfs-server now Requires rpcbind.service (bz 1171603) + +* Thu Jun 11 2015 Steve Dickson 1.3.0-0.11 +- Added the rpcuser group before adding the rpcuser uid (bz 1190874) +- Added back variables to help get through firewalls (bz 1208488) +- Made the postuns conditional (bz 1200713) + +* Mon May 4 2015 Steve Dickson 1.3.0-0.10 +- Updated mountstats to latest upstream version (bz 1215808) +- Enable all auth flavors on pseudofs exports (bz 1187223) + +* Tue Apr 28 2015 Steve Dickson 1.3.0-0.9 +- Updates for block pNFS (bz 1214821) + +* Fri Jan 23 2015 Steve Dickson 1.3.0-0.8 +- Stop sm-notify from running in HA environments (bz 1182692) +- Set the GSS_USE_PROXY variable in nfs-utils_env.sh (bz 1183821) + +* Thu Jan 15 2015 Steve Dickson 1.3.0-0.7 +- rpc.idmapd now comes down with the nfs server (bz 1159234) + +* Wed Jan 7 2015 Steve Dickson 1.3.0-0.6 +- Corrected argument names in the systemd scripts (bz 1170364) +- Added RELRO check (bz 1092543) +- Properly parse IPv6 literal strings with null termination (bz 1161490) +- Added the 'nordirplus' export flag to disable v3 readdirplus (bz 1161458) + +* Fri Nov 14 2014 Steve Dickson 1.3.0-0.5 +- Fixed a mound DOS (bz 1163891) + +* Fri Oct 24 2014 Steve Dickson 1.3.0-0.4 +- Added verbosity back to umount (bz 923582) + +* Wed Oct 15 2014 Steve Dickson 1.3.0-0.3 +- Enable gssproxy in /etc/sysconf/nfs (bz 1082746) + +* Mon Sep 29 2014 Steve Dickson 1.3.0-0.2 +- Upgrade to latest upstream systemd scripts (bz 1144440) +- Taught start-statd to use systemd (bz 1144440) +- Repaced rpc.svcgssd with gssproxy (bz 1082746) + +* Fri Sep 19 2014 Steve Dickson 1.3.0-0.1 +- Added configurable timeout to rpc.gssd (bz 1009528) +- Added callback to sm_notify (bz 1108105) +- mountd: Fixed path in start-statd (bz 1116794) +- rpc.gssd: Fixed silent error message (bz 1117384) +- rpc.gssd: add the acceptor name to the info passed in downcall (bz 1088011) +- nfs-utils.spec: fixed runtime configuration files (bz 1118177) +- exportfs: fix test of NULL pointer in host_pton() (bz 1083018) +- gssd: Fixed errno typo in get_servername() (bz 1082480) +- nfsiostat: documented the output better (bz 1109864) + +* Wed Mar 26 2014 Steve Dickson 1.3.0-0.0 +- Updated to latest upstream release: nfs-utils-1-3-0 + - mount.nfs: Fix fallback from tcp to udp (bz 984901) + - nfsidmap: Keys need to be invalidated instead of revoked (bz 1080505) +- Removed RDMA_PORT stub from /etc/sysconfig/nfs (bz 1078792) + +* Fri Jan 24 2014 Daniel Mach - 1:1.2.9-4 +- Mass rebuild 2014-01-24 + +* Thu Jan 23 2014 Steve Dickson 1.2.9-3.1 +- gssd: set $HOME to prevent recursion when home dirs are on kerberized NFS mount (bz 1056658) + +* Mon Jan 20 2014 Steve Dickson 1.2.9-3.0 +- Updated to the latest upstream RC release nfs-utils-1.2.10-rc3 + - exportfs: Exit with correct value when an error occurs (bz 1053933) + - mount.nfs: Removed supported flag from usage string (bz 1000989) + - gssd: Improve first attempt at acquiring GSS credentials (bz 1053877) + - rpc.idmapd: Remove no longer supported flags from man page (bz 1003513) + - rpc.statd: Allow usage messages to be displayed when statd is running. (bz 1037044) + +* Wed Jan 8 2014 Steve Dickson 1.2.9-2.1 +- exportfs: Remove a buffer overlow (bz 1008384) +- nfs-server: Added an Also cause (bz 1050161) + +* Wed Jan 8 2014 Steve Dickson 1.2.9-2.0 +- Updated to the latest upstream RC release nfs-utils-1.2.10-rc2 + - mount.nfs: Eliminated long delays during mount (bz 1031643) + - exportfs: Corrected erroneously error messages (bz 1049589) + +* Tue Jan 7 2014 Steve Dickson 1.2.9-0.5 +- Reverted patch for bz1029573. The kernel can now detect + when rpc.gssd is or is not running (bz1031197) +- gssd: always reply to rpc-pipe requests from kernel. (bz1031197) + +* Fri Dec 27 2013 Daniel Mach - 1:1.2.9-0.4 +- Mass rebuild 2013-12-27 + +* Tue Nov 12 2013 Steve Dickson 1.2.9-0.3 +- The patch for bz 1029573 had a zero length due a typo (bz 1029573) + +* Tue Nov 12 2013 Steve Dickson 1.2.9-0.2 +- gssd will return immediately when a keytab is not readable (bz 1029573) + +* Thu Nov 7 2013 Steve Dickson 1.2.9-0.1 +- Reordered how mountd and nfsd are started (bz 963138) + +* Tue Nov 5 2013 Steve Dickson 1.2.9-0.0 +- Updated to latest upstream Release: nfs-utils-1-2-9 +- Fixed a mounting error (bz 963580) + +* Thu Aug 22 2013 Steve Dickson 1.2.8-4.1 +- nfs-utils: fix a number of specfile problems + +* Mon Aug 19 2013 Steve Dickson 1.2.8-4.0 +- Updated to latest upstream RC release: nfs-utils-1-2-9-rc4 + +* Tue Jul 23 2013 Steve Dickson 1.2.8-3.0 +- Updated to latest upstream RC release: nfs-utils-1-2-9-rc3 + +* Tue Jul 23 2013 Steve Dickson 1.2.8-2.1 +- Make sure nfs.target is enabled (bz 970595) +- Fix nfs server reloads (bz 951247) + +* Fri May 31 2013 Steve Dickson 1.2.8-2.0 +- Update to latest upstream RC release: nfs-utils.1.2.9-rc1 +- Added GSS_USE_PROXY variable to nfs.sysconfig (bz 967112) + +* Tue May 7 2013 Steve Dickson 1.2.8-1.1 + systemd: nfs-server.service needs to be split up (bz 769879) + +* Tue May 7 2013 Steve Dickson 1.2.8-1 +- Updated to the latest upstream RC release: nfs-utils.1.2.9-rc1 + +* Tue Apr 23 2013 Steve Dickson 1.2.8-0 +- Updated to latest upstream release: 1.2.8 +- Removed the libgssglue dependency + +* Mon Apr 1 2013 Steve Dickson 1.2.7-6 +- Added v4.1 support rpc.nfsd (bz 947073) + +* Mon Mar 25 2013 Steve Dickson 1.2.7-5 +- Updated to latest upstream RC release: nfs-utils.1.2.8-rc4 +- Added nfs-lock.service to After line in nfs-server.service (bz 914792) + +* Thu Feb 14 2013 Fedora Release Engineering - 1:1.2.7-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Jan 16 2013 Steve Dickson 1.2.7-3 +- Updated to latest upstream RC release: nfs-utils.1.2.8-rc3 +- Took ownership of /usr/lib/nfs-utils (bz 894535) + +* Mon Dec 17 2012 Steve Dickson 1.2.7-2 +- Update to latest upstream RC release: nfs-utils.1.2.8-rc2 + +* Wed Nov 28 2012 Steve Dickson 1.2.7-1 +- Update to latest upstream RC release: nfs-utils.1.2.8-rc1 + +* Fri Nov 9 2012 Steve Dickson 1.2.7-0 +- Updated to latest upstream release: nfs-utils.1.2.7 + +* Thu Nov 8 2012 Steve Dickson 1.2.6-14 +- Allow the service to start when RPCNFSDCOUNT is comment out. (bz 870143) +- Removed some old cruft from the spec file (bz 226198) + +* Mon Oct 15 2012 Steve Dickson 1.2.6-13 +- Added a Requires for the quota package (bz 866225) + +* Thu Aug 23 2012 Steve Dickson 1.2.6-12 +- Added FedFS support by added a BuildRequires for fedfs-utils-devel +- Introduce new systemd-rpm macros (bz 850227) +- Updated to latest upstream RC release: nfs-utils.1.2.7-rc5 (bz 833024) + +* Mon Aug 6 2012 Steve Dickson 1.2.6-11 +- Updated to latest upstream RC release: nfs-utils.1.2.7-rc4 + +* Thu Aug 2 2012 Steve Dickson 1.2.6-10 +- Removed modprobe.d/nfs.conf + +* Thu Jul 19 2012 Steve Dickson 1.2.6-9 +- Updated to latest upstream RC release: nfs-utils.1.2.7-rc3 + +* Thu Jul 5 2012 Steve Dickson 1.2.6-8 +- nfsidmap: default domain no being set (bz 829362) + +* Fri Jun 22 2012 Steve Dickson 1.2.6-7 +- Reworked how the legacy names are enabled in systemd +- Fixed typo in nfs-mountd.service + +* Tue Jun 12 2012 Steve Dickson 1.2.6-6 +- Updated to latest upstream RC release: nfs-utils.1.2.7-rc2 (bz 833555) + +* Tue Jun 12 2012 Steve Dickson 1.2.6-5 +- Reworked how the services are restarted. + +* Tue Jun 12 2012 Steve Dickson 1.2.6-4 +- Enable legacy service names. + +* Tue May 29 2012 Steve Dickson 1.2.6-3 +- Updated to latest upstream RC release: nfs-utils.1.2.7-rc1 + +* Tue May 29 2012 Steve Dickson 1.2.6-2 +* Fixed typo in the checking of nfsnobody (bz 816149) + +* Fri May 25 2012 Steve Dickson 1.2.6-1 +- Correctly search for the existence of nfsnobody (bz 816149) +- Correctly change the default group id for nfsnobody (bz 816149) + +* Tue May 15 2012 Steve Dickson 1.2.6-0 +- Update to the latest upstream release: nfs-utils-1.2.6 (bz 821673) +- Split out NFS server daemons into individual service files (bz 769879) +- Removed Wants= from nfs-lock.service (bz 817895) +- Only enable services if they are enabled on upgrades (bz 807020) + +* Thu May 3 2012 Steve Dickson 1.2.5-16 +- Update to the latest RC release: nfs-utils-1.2.6-rc7 + +* Thu Apr 26 2012 Josh Boyer 1.2.5-15 +- Add modprobe config file to alias 'nfs4' to 'nfs' (bz 806333) + +* Thu Mar 22 2012 Steve Dickson 1.2.5-14 +- gssd: Look for user creds in user defined directory (bz 786993) +- gssd: Don't link with libgssapi_krb5 (bz 784908) + +* Fri Mar 16 2012 Steve Dickson 1.2.5-13 +- Make sure statd is start before NFS mounts (bz 786050) +- rpc.idmap: Hide global symbols from libidmap plugins (bz 797332) +- nfsd: Bump up the default to 8 nprocs (bz 757452) + +* Wed Feb 08 2012 Harald Hoyer 1.2.5-12 +- require kmod instead of modutils (bz 788571) + +* Mon Jan 16 2012 Steve Dickson 1.2.5-11 +- Update to upstream RC release: nfs-utils-1.2.6-rc6 +- Reworked how the nfsd service requires the rpcbind service (bz 768550) + +* Mon Jan 9 2012 Steve Dickson 1.2.5-10 +- Added back the SUID bits on mount commands (bz 772396) +- Added a decency on keyutils (bz 769724) + +* Thu Jan 5 2012 Steve Dickson 1.2.5-9 +- Update to upstream RC release: nfs-utils-1.2.6-rc5 + +* Thu Dec 15 2011 Steve Dickson 1.2.5-8 +- Removed the nfs-idmap service. rpc.idmap is now part of + the nfs-server service + +* Tue Dec 13 2011 Steve Dickson 1.2.5-7 +- Enabled new idmaping by installing the id_resolver.conf file. +- Update to upstream RC release: nfs-utils-1.2.6-rc4 + +* Fri Nov 18 2011 Steve Dickson 1.2.5-6 +- Remove RQUOTAD_PORT and RQUOTAD from /etc/sysconfig/nfs (bz 754496) +- Ensured nfs-idmap service is started after the named is up (bz 748275) + +* Mon Nov 14 2011 Steve Dickson 1.2.5-5 +- Ensured nfs-idmap service is started after the network up (bz 748275) +- Update to upstream RC release: nfs-utils-1.2.6-rc3 (bz 746497) + +* Thu Oct 20 2011 Steve Dickson 1.2.5-4 +- Added pNFS debugging to rpcdebug. + +* Tue Oct 18 2011 Steve Dickson 1.2.5-3 +- Update to upstream RC release: nfs-utils-1.2.6-rc2 + +* Tue Oct 4 2011 Steve Dickson 1.2.5-2 +- Removed SUID bits on mount commands (bz 528498) +- Fixed a few typos in a couple man pages (bz 668124, 673818, 664330) +- Fixed a I/0 problem in rpc.idmapd (bz 684308) + +* Mon Oct 3 2011 Steve Dickson 1.2.5-1 +- Update to upstream RC release: nfs-utils-1.2.6-rc1 +- Added named.service to After list in nfs-server.service (bz 742746) + +* Tue Sep 27 2011 Steve Dickson 1.2.5-0 +- Update to upstream release: nfs-utils-1.2.5 (bz 717931) + +* Wed Sep 21 2011 Steve Dickson 1.2.4-11 +- Update to upstream RC release: nfs-utils-1.2.5-rc3 + +* Wed Sep 14 2011 Steve Dickson 1.2.4-10 +- Created /etc/exports.d to stop a warning (bz 697006) + +* Tue Aug 30 2011 Steve Dickson 1.2.4-9 +- Both the nfs.lock and nfs.idmap services should always + enabled on both installs and upgrades (bz 699040) +- Fixed the paths to the server scriptlets (bz 733531) + +* Mon Aug 29 2011 Steve Dickson 1.2.4-8 +- Update to upstream RC release: nfs-utils-1.2.5-rc2 + +* Wed Aug 24 2011 Steve Dickson 1.2.4-7 +- Added StandardError=syslog+console to all the service files + so startup errors will be logged. +- Changed exportfs to only log errors on existing /etc/export.d + directory, which eliminates a needless syslog entry. +- Automount /proc/fs/nfsd for rpc.nfsd + +* Wed Aug 10 2011 Steve Dickson 1.2.4-6 +- Fixed some bugs in the triggerun script as well in + the nfs-server scripts (bz 699040). + +* Wed Aug 3 2011 Steve Dickson 1.2.4-5 +- Cleaned up the .preconfig and .postconfig files per + code review request. + +* Wed Aug 3 2011 Steve Dickson 1.2.4-4 +- Converted init scrips to systemd services. (bz 699040) +- Made nfsnobody's uid/gid to always be a 16-bit value of -2 +- mount: fix for libmount from util-linux >= 2.20 + +* Thu Jul 21 2011 Steve Dickson 1.2.4-3 +- Updated to latest upstream release: nfs-utils-1-2-5-rc1 + +* Thu Jul 7 2011 Ville Skyttä - 1:1.2.4-2 +- Don't ship Makefiles or INSTALL in docs (#633934). + +* Mon Jul 4 2011 J. Bruce Fields 1.2.4-1 +- Rely on crypto module autoloading in init scripts +- initscripts: just try to mount rpc_pipefs always + +* Wed Jun 29 2011 Steve Dickson 1.2.4-0 +- Updated to latest upstream release: nfs-utils-1-2-4 + +* Wed Apr 20 2011 Steve Dickson 1.2.3-13 +- Updated to latest upstream release: nfs-utils-1-2-4-rc8 + +* Wed Apr 6 2011 Steve Dickson 1.2.3-12 +- Updated to latest upstream release: nfs-utils-1-2-4-rc7 +- Enabled the libmount code. + +* Mon Mar 7 2011 Steve Dickson 1.2.3-11 +- Updated to latest upstream release: nfs-utils-1-2-4-rc6 + +* Wed Feb 09 2011 Christopher Aillon - 1.2.3-10 +- Rebuild against newer libevent + +* Tue Feb 08 2011 Fedora Release Engineering - 1:1.2.3-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Jan 26 2011 Steve Dickson 1.2.3-8 +- Fixed segfault in rpc.mountd (bz 669065) + +* Fri Jan 14 2011 Steve Dickson 1.2.3-7 +- Updated to latest upstream release: nfs-utils-1-2-4-rc5 +- Add initscripts changes needed for rpcbind to be running when nfs is started +- Initscripts changes needed to support NFS over RDMA +- Allow the setting of the NFSv4 grace period (bz 665387) + +* Mon Dec 13 2010 Steve Dickson 1.2.3-6 +- Updated to latest upstream release: nfs-utils-1-2-4-rc4 + +* Wed Dec 8 2010 Steve Dickson 1.2.3-5 +- Replace the nfs-utils-lib dependency with a libnfsidmap + dependency + +* Wed Dec 1 2010 Steve Dickson 1.2.3-4 +- The nfs service is not stopped on reboot or halt (bz 652786) +- Removed obsolete configuration values (bz 653765) + +* Mon Nov 29 2010 Steve Dickson 1.2.3-3 +- Updated to latest upstream release: nfs-utils-1-2-4-rc3 + +* Fri Oct 15 2010 Steve Dickson 1.2.3-2 +- Initscripts do not conform to LSB specification (bz 621562) +- sm-notify needs to call res_init() before each try (bz 625531) +- exports(5) man page duplicated paragraphs (bz 590921) + +* Thu Oct 14 2010 Steve Dickson 1.2.3-1 +- Updated to latest upstream release: nfs-utils-1-2-4-rc1 + +* Mon Oct 4 2010 Steve Dickson 1.2.3-0.1 +- Fixed a regession with -p arguemnt to rpc.mountd + +* Thu Sep 30 2010 Steve Dickson 1.2.3-0 +- Updated to latest upstream release: nfs-utils-1-2-3 + +* Thu Sep 16 2010 Steve Dickson 1.2.2-8 +- Update to upstream RC release: nfs-utils-1-2-3-rc6 + +* Thu Sep 9 2010 Steve Dickson 1.2.2-7 +- Update to upstream RC release: nfs-utils-1-2-3-rc5 + +* Tue Jun 22 2010 Steve Dickson 1.2.2-6 +- Update to upstream RC release: nfs-utils-1-2-3-rc4 + +* Thu May 6 2010 Steve Dickson 1.2.2-4 +- Update to upstream RC release: nfs-utils-1-2-3-rc3 + +* Fri Apr 16 2010 Steve Dickson 1.2.2-3 +- Update to upstream RC release: nfs-utils-1-2-3-rc2 + +* Mon Mar 22 2010 Steve Dickson 1.2.2-2 +- Update to upstream RC release: nfs-utils-1-2-3-rc1 + +* Thu Feb 18 2010 Steve Dickson 1.2.2-1 +- Updated to latest upstream version: 1.2.2 + +* Thu Jan 28 2010 Steve Dickson 1.2.1-17 +- Backed out the "Don't fail mounts when /etc/netconfig is + nonexistent" patch + +* Wed Jan 27 2010 Steve Dickson 1.2.1-16 +- mount.nfs: Don't fail mounts when /etc/netconfig is nonexistent + +* Mon Jan 25 2010 Steve Dickson 1.2.1-15 +- statd: Teach nfs_compare_sockaddr() to handle NULL + arguments + +* Fri Jan 22 2010 Steve Dickson 1.2.1-14 +- Update to upstream RC release: nfs-utils-1-2-2-rc9 + +* Thu Jan 21 2010 Steve Dickson 1.2.1-13 +- mount.nfs: Configuration file parser ignoring options +- mount.nfs: Set the default family for lookups based on + defaultproto= setting +- Enabled ipv6 + +* Sun Jan 17 2010 Steve Dickson 1.2.1-12 +- Updated to latest upstream RC release: nfs-utils-1-2-2-rc7 + which includes Ipv6 support for tcpwrapper (disabled by default). + +* Sat Jan 16 2010 Steve Dickson 1.2.1-11 +- Updated to latest upstream RC release: nfs-utils-1-2-2-rc7 + which includes Ipv6 support for statd (disabled by default). + +* Thu Jan 14 2010 Steve Dickson 1.2.1-10 +- Updated to the latest pseudo root release (rel10) which + containts the upstream pseudo root release + +* Tue Jan 12 2010 Steve Dickson 1.2.1-9 +- Updated to latest upstream RC release: nfs-utils-1-2-2-rc5 + +* Mon Jan 4 2010 Steve Dickson 1.2.1-8 +- mount.nfs: don't use IPv6 unless IPV6_SUPPORTED is set + +* Mon Dec 14 2009 Steve Dickson 1.2.1-7 +- Updated to latest upstream RC release: nfs-utils-1-2-2-rc3 + +* Thu Dec 10 2009 Steve Dickson 1.2.1-6 +- Update the pseudo root to handle security flavors better. + +* Mon Dec 7 2009 Steve Dickson 1.2.1-5 +- mount.nfs: Retry v4 mounts with v3 on ENOENT errors + +* Mon Dec 7 2009 Steve Dickson 1.2.1-4 +- Updated to the latest pseudo root release (rel9) (bz 538609). + +* Thu Nov 12 2009 Steve Dickson 1.2.1-3 +- Stop rpc.nfsd from failing to startup when the network + is down (bz 532270) + +* Wed Nov 11 2009 Steve Dickson 1.2.1-2 +- Updated to the latest pseudo root release (rel8). + +* Wed Nov 4 2009 Steve Dickson 1.2.1-1 +- Updated to latest upstream release: 1.2.0 + +* Tue Nov 3 2009 Steve Dickson 1.2.0-18 +- Reworked and remove some of the Default-Start/Stop stanzas + in the init scripts (bz 531425) + +* Mon Nov 2 2009 Steve Dickson 1.2.0-17 +- Updated to the latest pseudo root release (rel7). +- Added upstream 1.2.1-rc7 patch which fixes: + - Stop ignoring the -o v4 option (bz 529407) + - Allow network protocol roll backs when proto is set + in the config file (bz 529864) +- v4 mounts will roll back to v3 mounts when the mount + fails with ENOENT. + +* Mon Oct 5 2009 Steve Dickson 1.2.0-16 +- Fixed a whole where '-o v4' was not overriding the + version in the conf file. + +* Wed Sep 30 2009 Steve Dickson 1.2.0-15 +- Change the nfsmount.conf file to define v3 as the default + protocol version. +- Make sure versions set on the command line override version + set in nfsmount.conf +- Make version rollbacks still work when versions are set in + nfsmount.conf + +* Tue Sep 29 2009 Steve Dickson 1.2.0-13 +- Added upstream 1.2.1-rc5 patch + - mount.nfs: Support negotiation between v4, v3, and v2 + - mount.nfs: Keep server's address in nfsmount_info + - mount.nfs: Sandbox each mount attempt + - mount.nfs: Support negotiation between v4, v3, and v2 + +* Wed Sep 23 2009 Steve Dickson 1.2.0-12 +- Updated to the latest pseudo root release (rel6). + +* Tue Sep 15 2009 Steve Dickson 1.2.0-11 +- Added upstream 1.2.1-rc5 patch + - Added --sort --list functionality to nfs-iostat.py + - Fixed event handler in idmapd + - Added -o v4 support + - Disabled IPv6 support in nfsd + - Don't give client an empty flavor list + - Fixed gssed so it does not blindly caches machine credentials + +* Mon Aug 17 2009 Steve Dickson 1.2.0-10 +- Added upstream 1.2.1-rc4 patch + - Fix bug when both crossmnt + - nfs(5): Add description of lookupcache mount option + - nfs(5): Remove trailing blanks + - Added nfs41 support to nfssat + - Added support for mount to us a configuration file. + +* Fri Aug 14 2009 Steve Dickson 1.2.0-9 +- Added upstream 1.2.1-rc3 patch + - Add IPv6 support to nfsd + - Allow nfssvc_setfds to properly deal with AF_INET6 + - Convert nfssvc_setfds to use getaddrinfo + - Move check for active knfsd to helper function + - Declare a static common buffer for nfssvc.c routine + - Convert rpc.nfsd to use xlog() and add --debug and --syslog options + +* Tue Jul 28 2009 Steve Dickson 1.2.0-8 +- Fixed 4.1 versioning problem (bz 512377) + +* Wed Jul 15 2009 Steve Dickson 1.2.0-7 +- Added upstream 1.2.1-rc2 patch + - A large number of mount command changes. + +* Mon Jul 13 2009 Steve Dickson 1.2.0-6 +- Added NFSD v4 dynamic pseudo root patch which allows + NFS v3 exports to be mounted by v4 clients. + +* Mon Jun 29 2009 Steve Dickson 1.2.0-5 +- Stopped rpc.idmapd from spinning (bz 508221) + +* Mon Jun 22 2009 Steve Dickson 1.2.0-4 +- Added upstream 1.2.1-rc1 patch + - Fix to check in closeall() + - Make --enable-tirpc the default + - Set all verbose types in gssd daemons + - Retry exports if getfh() fails + +* Wed Jun 10 2009 Steve Dickson 1.2.0-3 +- Updated init scripts to add dependencies + on other system facilities (bz 475133) + +* Wed Jun 10 2009 Steve Dickson 1.2.0-2 +- nfsnobody gid is wrong (bz 485379) + +* Tue Jun 2 2009 Steve Dickson 1.2.0-1 +- Updated to latest upstream release: 1.2.0 + +* Tue May 19 2009 Tom "spot" Callaway 1.1.6-4 +- Replace the Sun RPC license with the BSD license, with the explicit permission of Sun Microsystems + +* Mon May 18 2009 Steve Dickson 1.1.6-3 +- Added upstream 1.1.7-rc1 patch + - utils/nfsd: add support for minorvers4 + - sm-notify: Don't orphan addrinfo structs + - sm-notify: Failed DNS lookups should be retried + - mount: remove legacy version of nfs_name_to_address() + - compiling error in rpcgen + - nfs-utils: Fix IPv6 support in support/nfs/rpc_socket.c + - umount.nfs: Harden umount.nfs error reportin + +* Mon Apr 27 2009 Steve Dickson 1.1.6-2 +- nfslock.init: options not correctly parsed (bz 459591) + +* Mon Apr 20 2009 Steve Dickson 1.1.6-1 +- Updated to latest upstream release: 1.1.6 + +* Mon Mar 23 2009 Steve Dickson 1.1.5-4 +- Added upstream rc3 patch + - gssd: initialize fakeseed in prepare_krb5_rfc1964_buffer + - gssd: NULL-terminate buffer after read in read_service_info (try #2) + - gssd: free buffer allocated by gssd_k5_err_msg + - gssd: fix potential double-frees in gssd + - Removed a number of warn_unused_result warnings + +* Mon Mar 16 2009 Steve Dickson 1.1.5-3 +- Added upstream rc2 patch + +* Fri Mar 6 2009 Steve Dickson 1.1.5-2 +- Fixed lockd not using settings in sysconfig/nfs (bz 461043) +- Fixed some lost externs in the tcpwrapper code + +* Thu Mar 5 2009 Steve Dickson 1.1.5-1 +- Updated to latest upstream version: 1.1.5 + +* Wed Mar 4 2009 Steve Dickson 1.1.4-21 +- configure: fix AC_CACHE_VAL warnings + +* Wed Feb 25 2009 Fedora Release Engineering - 1:1.1.4-20 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Wed Feb 18 2009 Steve Dickson 1.1.4-19 +- Exportfs and rpc.mountd optimalization (bz 76643) + +* Tue Feb 17 2009 Steve Dickson 1.1.4-18 +- umount.nfs command: Add an AF_INET6-capable version of nfs_call_unmount() +- umount.nfs command: Support AF_INET6 server addresses +- umount command: remove do_nfs_umount23 function + +* Tue Feb 17 2009 Steve Dickson 1.1.4-17 +- Integrated the upstream fix for bz 483375 +- mount: segmentation faults on UDP mounts (bz 485448) + +* Sat Jan 31 2009 Steve Dickson 1.1.4-16 +- Fixed typo in -mount-textbased.patch (bz 483375) + +* Sat Jan 31 2009 Steve Dickson 1.1.4-15 +- Reworked tcp wrapper code to correctly use API (bz 480223) +- General clean up of tcp wrapper code. + +* Tue Jan 27 2009 Steve Dickson 1.1.4-14 +- text-based mount command: make po_rightmost() work for N options +- text-based mount command: Function to stuff "struct pmap" from mount options +- text-based mount options: Use new pmap stuffer when rewriting mount options +- text-based mount command: fix mount option rewriting logic +- text-based mount command: support AF_INET6 in rewrite_mount_options() + +* Tue Jan 20 2009 Steve Dickson 1.1.4-13 +- mountd: Don't do tcp wrapper check when there are no rules (bz 448898) + +* Wed Jan 7 2009 Steve Dickson 1.1.4-12 +- configure: Remove inet_ntop(3) check from configure.ac +- configure: Add new build option "--enable-tirpc" +- showmount command: Quiesce warning when TI-RPC is disabled + +* Sat Jan 3 2009 Steve Dickson 1.1.4-11 +- Added warnings to tcp wrapper code when mounts are + denied due to misconfigured DNS configurations. +- gssd: By default, don't spam syslog when users' credentials expire +- mount: revert recent fix for build problems on old systems +- mount: use gethostbyname(3) when building on old systems +- mount: getport: don't use getaddrinfo(3) on old systems +- mount: Random clean up +- configure: use "--disable-uuid" instead of "--without-uuid" + +* Fri Dec 19 2008 Steve Dickson 1.1.4-10 +- Re-enabled and fixed/enhanced tcp wrappers. + +* Wed Dec 17 2008 Steve Dickson 1.1.4-9 +- text-based mount command: add function to parse numeric mount options +- text-based mount command: use po_get_numeric() for handling retry +- sm-notify command: fix a use-after-free bug +- statd: not unlinking host files + +* Thu Dec 11 2008 Steve Dickson 1.1.4-8 +- mount command: AF_INET6 support for probe_bothports() +- mount command: support AF_INET6 in probe_nfsport() and probe_mntport() +- mount command: full support for AF_INET6 addresses in probe_port() +- gssd/svcgssd: add support to retrieve actual context expiration +- svcgssd: use the actual context expiration for cache + +* Sat Dec 6 2008 Steve Dickson 1.1.4-7 +- sm-notify: always exiting without any notification. + +* Tue Dec 2 2008 Steve Dickson 1.1.4-6 +- mount command: remove local getport() implementation +- mount command: Replace clnt_ping() and getport() calls in probe_port() +- mount command: Use nfs_error() instead of perror() +- mount command: Use nfs_pmap_getport() in probe_statd() + +* Mon Dec 1 2008 Steve Dickson 1.1.4-5 +- Make sure /proc/fs/nfsd exists when the nfs init script + does the exports (bz 473396) +- Fixed typo in nfs init script that caused rpc.rquotad daemons + to be started but not stoppped (bz 473929) + +* Wed Nov 26 2008 Steve Dickson 1.1.4-4 +- gssd: unblock DNOTIFY_SIGNAL in case it was blocked +- Ensure statd gets started if required when non-root + user mounts an NFS filesystem + +* Tue Nov 25 2008 Steve Dickson 1.1.4-3 +- Give showmount support for querying via rpcbindv3/v4 + +* Tue Nov 18 2008 Steve Dickson 1.1.4-2 +- Add AF_INET6-capable API to acquire an RPC CLIENT +- Introduce rpcbind client utility functions + +* Sat Oct 18 2008 Steve Dickson 1.1.4-1 +- Updated to latest upstream version: 1.1.4 + +* Tue Oct 14 2008 Steve Dickson 1.1.3-6 +- sm-notify exists when there are no hosts to notify + +* Thu Sep 18 2008 Steve Dickson 1.1.3-5 +- Reworked init scripts so service will be able to + stop when some of the checks fail. (bz 462508) +- Pre-load nfsd when args to rpc.nfsd are given (bz 441983) + +* Thu Aug 28 2008 Steve Dickson 1.1.3-4 +- Added in a number of up upstream patches (101 thru 110). + +* Mon Aug 11 2008 Tom "spot" Callaway 1.1.3-3 +- fix license tag + +* Thu Jul 31 2008 Steve Dickson 1.1.3-2 +- Mount command did not compile against older glibc versions. + +* Mon Jul 28 2008 Steve Dickson 1.1.3-1 +- Updated to latest upstream version: 1.1.3 + +* Wed Jul 2 2008 Steve Dickson 1.1.2-12 +- Changed the default directories for sm-notify (bz 435480) +- Added 'condstop' to init scripts so service are not + started when nfs-utils is removed. + +* Mon Jun 30 2008 Dennis Gilmore 1.1.2-11 +- add sparc arch handling + +* Mon Jun 30 2008 Steve Dickson 1.1.2-10 +- Rebuild for the updated libevent lib. + +* Fri Jun 27 2008 Steve Dickson 1.1.2-9 +- Removed the nfslock service start/stop from %%post section + (bz 453046) + +* Wed Jun 25 2008 Steve Dickson 1.1.2-8 +- FQDNs in the rmtab causes exportfs to seg fault (bz 444275) + +* Mon Jun 23 2008 Steve Dickson 1.1.2-7 +- Added -D_FILE_OFFSET_BITS=64 to CFLAGS +- make nfsstat read and print stats as unsigned integers +- Added (but not installed) the mountstats and nfs-iostat + python scripts. + +* Fri Jun 6 2008 Steve Dickson 1.1.2-6 +- Added 5 (111 thru 115) upstream patches that fixed + things mostly in the text mounting code. + +* Thu May 8 2008 Steve Dickson 1.1.2-5 +- Added 10 (101 thru 110) upstream patches that fixed + things mostly in the mount and gssd code. + +* Wed May 7 2008 Steve Dickson 1.1.2-4 +- Added ppc arch to the all_32bit_archs list (bz 442847) + +* Wed Apr 23 2008 Steve Dickson 1.1.2-3 +- Documented how to turn off/on protocol support for + rpc.nfsd in /etc/sysconfig/nfs (bz443625) +- Corrected the nfslock initscript 'status' return code (bz 441605) +- Removed obsolete code from the nfslock initscript (bz 441604) + +* Mon Apr 14 2008 Steve Dickson 1.1.2-2 +- Make EACCES a non fatal error (bz 439807) + +* Tue Mar 25 2008 Steve Dickson 1.1.2-1 +- Upgrade to nfs-utils-1.1.2 + +* Mon Mar 3 2008 Steve Dickson 1.1.1-5 +- Stopped mountd from incorrectly logging an error + (commit 9dd9b68c4c44f0d9102eb85ee2fa36a8b7f638e3) +- Stop gssd from ignoring the machine credential caches + (commit 46d439b17f22216ce8f9257a982c6ade5d1c5931) +- Fixed typo in the nfsstat command line arugments. + (commit acf95d32a44fd8357c24e8a04ec53fc6900bfc58) +- Added test to stop buffer overflow in idmapd + (commit bcd0fcaf0966c546da5043be700587f73174ae25) + +* Sat Feb 9 2008 Steve Dickson 1.1.1-4 +- Cleaned up some typos that were found in the various + places in the mountd code + +* Thu Jan 24 2008 Steve Dickson 1.1.1-3 +- Added in relatime mount option so mount.nfs stays + compatible with the mount command in util-linux-ng (bz 274301) + +* Tue Jan 22 2008 Steve Dickson 1.1.1-2 +- Added -S/--since to the nfsstat(1) manpage +- The wording in the exportfs man page can be a bit confusing, implying + that "exportfs -u :/foo" will unexport /foo from all hosts, which it won't +- Removed nfsprog option since the kernel no longer supports it. +- Removed mountprog option since the kernel no longer supports it. +- Stop segfaults on amd64 during warnings messages. +- Fix bug when both crossmnt and fsid are set. + +* Sat Jan 5 2008 Steve Dickson 1.1.1-1 +- Updated to latest upstream release, nfs-utils-1.1.1 +- Added the removal of sm-notify.pid to nfslock init script. +- Changed spec file to use condrestart instead of condstop + when calling init scripts. +- Fixed typo in rpc.mountd man page +- Turn on 'nohide' automatically for all refer exports (bz 313561) + +* Tue Dec 04 2007 Release Engineering - 1.1.0-7 + - Rebuild for openldap bump + +* Wed Oct 17 2007 Steve Dickson 1.1.0-6 +- Switch the libgssapi dependency to libgssglue + +* Fri Sep 14 2007 Steve Dickson 1.1.0-5 +- Changed the default paths in sm-notify to + /var/lib/nfs/statd (bz 258461) +- Updated exportfs manpage (bz 262861) + +* Wed Aug 15 2007 Steve Dickson 1.1.0-4 +- Make sure the open() system calling in exportfs uses + mode bits when creating the etab file (bz 252440). + +* Mon Aug 13 2007 Steve Dickson 1.1.0-3 +- Added nosharecache mount option which re-enables + rw/ro mounts to the same server (bz 243913). + +* Thu Aug 2 2007 Steve Dickson 1.1.0-2 +- Make sure the gss and idmap daemons remove thier lock + files when they are stopped. + +* Sat Jul 28 2007 Steve Dickson 1.1.0-1 +- Upgraded to the latest upstream version (nfs-utils-1.1.0) + +* Thu May 24 2007 Steve Dickson 1.0.10-7 +- Fixed typo in mount.nfs4 that causes a segfault during + error processing (bz 241190) + +* Tue May 22 2007 Steve Dickson 1.0.10-6 +- Make sure the condrestarts exit with a zero value (bz 240225) +- Stopped /etc/sysconfig/nfs from being overwritten on updates (bz 234543) +- Added -o nordirplus mount option to disable READDIRPLUS (bz 240357) +- Disabled the FSCache patch, for now... + +* Thu May 10 2007 Steve Dickson 1.0.12-5 +- Fix mount.nfs4 to display correct error message (bz 227212) +- Updated mountd and showmount reverse lookup flags (bz 220772) +- Eliminate timeout on nfsd shutdowns (bz 222001) +- Eliminate memory leak in mountd (bz 239536) +- Make sure statd uses correct uid/gid by chowning + the /var/lib/nfs/statd with the rpcuser id. (bz 235216) +- Correct some sanity checking in rpc.nfsd. (bz 220887) +- Added missing unlock_mtab() call in moutnd +- Have mountd hold open etab file to force inode number to change (bz 236823) +- Create a /etc/sysconfig/nfs with all the possible init script + variables (bz 234543) +- Changed nfs initscript to exit with correct value (bz 221874) + +* Tue Apr 3 2007 Steve Dickson 1.0.12-4 +- Replace portmap dependency with an rpcbind dependency (bz 228894) + +* Mon Mar 12 2007 Steve Dickson 1.0.12-3 +- Incorporated Merge Review comments (bz 226198) + +* Fri Mar 9 2007 Steve Dickson 1.0.12-2 +- Added condstop to all the initscripts (bz 196934) +- Made no_subtree_check a default export option (bz 212218) + +* Tue Mar 6 2007 Steve Dickson 1.0.12-1 +- Upgraded to 1.0.12 +- Fixed typo in Summary. + +* Thu Mar 1 2007 Karel Zak 1.0.11-2 +- Fixed mount.nfs -f (fake) option (bz 227988) + +* Thu Feb 22 2007 Steve Dickson 1.0.11-1 +- Upgraded to 1.0.11 + +* Wed Feb 21 2007 Steve Dickson 1.0.10-7 +- Added FS_Location support + +* Mon Dec 18 2006 Karel Zak 1.0.10-6 +- add support for mount options that contain commas (bz 219645) + +* Wed Dec 13 2006 Steve Dickson 1.0.10-5 +- Stopped v4 umounts from ping rpc.mountd (bz 215553) + +* Tue Nov 28 2006 Steve Dickson 1.0.10-4 +- Doing a connect on UDP sockets causes the linux network + stack to reject UDP patches from multi-home server with + nic on the same subnet. (bz 212471) + +* Wed Nov 15 2006 Steve Dickson 1.0.10-3 +- Removed some old mounting versioning code that was + stopping tcp mount from working (bz 212471) + +* Tue Oct 31 2006 Steve Dickson 1.0.10-2 +- Fixed -o remount (bz 210346) +- fix memory leak in rpc.idmapd (bz 212547) +- fix use after free bug in dirscancb (bz 212547) +- Made no_subtree_check a default export option (bz 212218) + +* Wed Oct 25 2006 Steve Dickson 1.0.10-1 +- Upgraded to 1.0.10 + +* Mon Oct 16 2006 Steve Dickson 1.0.9-10 +- Fixed typo in nfs man page (bz 210864). + +* Fri Oct 13 2006 Steve Dickson 1.0.9-9 +- Unable to mount NFS V3 share where sec=none is specified (bz 210644) + +* Tue Sep 26 2006 Steve Dickson 1.0.9-8 +- mount.nfs was not returning a non-zero exit value + on failed mounts (bz 206705) + +* Wed Sep 20 2006 Karel Zak 1.0.9-7 +- Added support for the mount -s (sloppy) option (#205038) +- Added nfs.5 man page from util-linux +- Added info about [u]mount.nfs to the package description + +* Mon Sep 11 2006 1.0.9-6 +- Removed the compiling of getiversion and getkversion since + UTS_RELEASE is no longer defined and these binary are + not installed. + +* Fri Aug 18 2006 1.0.9-5 +- Changed gssd daemons to cache things in memory + instead of /tmp which makes selinux much happier. + (bz 203078) + +* Wed Aug 16 2006 1.0.9-4 +- Allow variable for HA callout program in /etc/init.d/nfslock + (bz 202790) + +* Wed Aug 02 2006 1.0.9-3 +- add epoch (#196359) + +* Fri Jul 28 2006 1.0.9-2 +- Enabled the creating of mount.nfs and umount.nfs binaries +- Added mount option fixes suggested by upstream. +- Fix lazy umounts (bz 169299) +- Added -o fsc mount option. + +* Mon Jul 24 2006 1.0.9-1 +- Updated to 1.0.9 release + +* Wed Jul 12 2006 Jesse Keating - 1:1.0.8-5.1 +- rebuild + +* Sun Jul 2 2006 1:1.0.8-5 +- Introduce epoch to fix upgrade path + +* Sat Jul 1 2006 1.0.8-3 +- Fixed typos in /etc/rc.d/init.d/nfs file (bz 184486) + +* Fri Jun 30 2006 1.0.8-3 +- Split the controlling of nfs version, ports, and protocol + into two different patches +- Fixed and added debugging statements to rpc.mountd. +- Fixed -p arg to work with priviledged ports (bz 156655) +- Changed nfslock initscript to set LOCKD_TCPPORT and + LOCKD_UDPPORT (bz 162133) +- Added MOUNTD_NFS_V1 variable to version 1 of the + mount protocol can be turned off. (bz 175729) +- Fixed gssd to handel mixed case characters in + the domainname. (bz 186069) + +* Wed Jun 21 2006 1.0.8-2 +- Updated to nfs-utils-1.0.8 + +* Thu Jun 8 2006 1.0.8.rc4-1 +- Upgraded to the upstream 1.0.8.rc4 version + +* Fri Feb 10 2006 Jesse Keating - 1.0.8.rc2-4.FC5.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.0.8.rc2-4.FC5.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Jan 20 2006 Steve Dickson 1.0.8.rc2-4.FC5 +- Added new libnfsidmap call, nfs4_set_debug(), to rpc.idmapd + which turns on debugging in the libarary. + +* Mon Jan 16 2006 Steve Dickson 1.0.8.rc2-3.FC5 +- Added innetgr patch that changes configure scripts to + check for the innetgr function. (bz 177899) + +* Wed Jan 11 2006 Peter Jones 1.0.8.rc2-2.FC5 +- Fix lockfile naming in the initscripts so they're stopped correctly. + +* Mon Jan 9 2006 Steve Dickson 1.0.8.rc2-1.FC5 +- Updated to 1.0.8-rc2 release +- Broke out libgssapi into its own rpm +- Move librpcsecgss and libnfsidmap in the new nfs-utils-lib rpm +- Removed libevent code; Required to be installed. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Sun Oct 23 2005 Steve Dickson 1.0.7-19 +- Updated to latest code in SourceForge CVS +- Updated to latest CITI patches (1.0.7-4) +- Fix bug in nfsdreopen by compiling in server defaults + +* Thu Sep 22 2005 Steve Dickson 1.0.7-18 +- Updated libnfsidmap to 0.11 +- Updated libgssapi to 0.5 +- Made sure the gss daemons and new libs are + all using the same include files. +- Removed code from the tree that is no longer used. +- Add ctlbits patch that introduced the -N -T and -U + command line flags to rpc.nfsd. + +* Sun Sep 18 2005 Steve Dickson 1.0.7-17 +- Updated to latest nfs-utils code in upstream CVS tree +- Updated libevent from 1.0b to 1.1a +- Added libgssapi-0.4 and librpcsecgss-0.6 libs from CITI + +* Thu Sep 8 2005 Steve Dickson 1.0.7-16 +- Reworked the nfslock init script so if lockd is running + it will be killed which is what the HA community needs. (bz 162446) +- Stopped rpcidmapd.init from doing extra echoing when + condstart-ed. + +* Wed Aug 24 2005 Peter Jones - 1.0.7-15 +- don't strip during "make install", so debuginfo packages are generated right + +* Thu Aug 18 2005 Florian La Roche +- no need to still keep a requirement for kernel-2.2 or newer + +* Tue Aug 16 2005 Steve Dickson 1.0.7-13 +- Changed mountd to use stat64() (bz 165062) + +* Tue Aug 2 2005 Steve Dickson 1.0.7-12 +- Changed useradd to use new -l flag (bz149407) +- 64bit fix in gssd code (bz 163139) +- updated broken dependencies +- updated rquotad to compile with latest + quota version. + +* Thu May 26 2005 Steve Dickson 1.0.7-8 +- Fixed subscripting problem in idmapd (bz 158188) + +* Thu May 19 2005 Steve Dickson 1.0.7-7 +- Fixed buffer overflow in rpc.svcgssd (bz 114288) + +* Wed Apr 13 2005 Steve Dickson 1.0.7-6 +- Fixed misformated output from nfslock script (bz 154648) + +* Tue Mar 29 2005 Steve Dickson 1.0.7-4 +- Fixed a compile error on x86_64 machines in the gss code. +- Updated the statd-notify-hostname.patch to eliminate + a segmentation fault in rpc.statd when an network + interface was down. (bz 151828) + +* Sat Mar 19 2005 Steve Dickson 1.0.7-3 +- Changed xlog to use LOG_INFO instead of LOG_DEBUG + so debug messages will appear w/out any config + changes to syslog.conf. +- Reworked how /etc/exports is setup (bz 151389) + +* Wed Mar 2 2005 Steve Dickson 1.0.7-2 +- Tied the rpcsecgss debugging in with gssd and + svcgssd debugging + +* Mon Feb 14 2005 Steve Dickson +- Added support to rpcgssd.init and rpcsvcgssd.init scripts + to insmod security modules. +- Changed the nfs.init script to bring rpc.svcgssd up and down, + since rpc.svcgssd is only needed with the NFS server is running. + +* Tue Dec 14 2004 Steve Dickson +- Fix problem in idmapd that was causing "xdr error 10008" + errors (bz 142813) +- make sure the correct hostname is used in the SM_NOTIFY + message that is sent from a rebooted server which has + multiple network interfaces. (bz 139101) + +- Changed nfslock to send lockd a -KILL signal + when coming down. (bz 125257) + +* Thu Nov 11 2004 Steve Dickson +- Replaced a memcopy with explicit assignments + in getquotainfo() of rquotad to fix potential overflow + that can occur on 64bit machines. (bz 138068) + +* Mon Nov 8 2004 Steve Dickson +- Updated to latest sourceforge code +- Updated to latest CITIT nfs4 patches + +* Sun Oct 17 2004 Steve Dickson +- Changed nfs.init to bring down rquotad correctly + (bz# 136041) + +* Thu Oct 14 2004 Steve Dickson +- Added "$RQUOTAD_PORT" variable to nfs.init which + allows the rpc.rquotad to use a predefined port + (bz# 124676) + +* Fri Oct 1 2004 +- Make sure the uid/gid of nfsnobody is the + correct value for all archs (bz# 123900) +- Fixed some security issues found by SGI (bz# 133556) + +* Mon Aug 30 2004 Steve Dickson +- Major clean up. +- Removed all unused/old patches +- Rename and condensed a number of patches +- Updated to CITI's nfs-utils-1.0.6-13 patches + +* Tue Aug 10 2004 Bill Nottingham +- move if..fi condrestart stanza to %%postun (#127914, #128601) + +* Wed Jun 16 2004 +- nfslock stop is now done on package removals +- Eliminate 3 syslog messages that are logged for + successful events. + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Mon Jun 14 2004 +- Fixed syntax error in nfs initscripts when + NETWORKING is not defined +- Removed sync warning on readonly exports. +- Changed run levels in rpc initscripts. +- Replaced modinfo with lsmod when checking + for loaded modules. + +* Tue Jun 1 2004 +- Changed the rpcgssd init script to ensure the + rpcsec_gss_krb5 module is loaded + +* Tue May 18 2004 +- Removed the auto option from MOUNTD_NFS_V2 and + MOUNTD_NFS_V3 variables. Since v2 and v3 are on + by default, there only needs to be away of + turning them off. + +* Mon May 10 2004 +- Rebuilt + +* Thu Apr 15 2004 +- Changed the permission on idmapd.conf to 644 +- Added mydaemon code to svcgssd +- Updated the add_gssd.patch from upstream + +* Wed Apr 14 2004 +- Created a pipe between the parent and child so + the parent process can report the correct exit + status to the init scripts +- Added SIGHUP processing to rpc.idmapd and the + rpcidmapd init script. + +* Mon Mar 22 2004 +- Make sure check_new_cache() is looking in the right place + +* Wed Mar 17 2004 +- Changed the v4 initscripts to use $prog for the + arugment to daemon + +* Tue Mar 16 2004 +- Made the nfs4 daemons initscripts work better when + sunrpc is not a module +- added more checks to see if modules are being used. + +* Mon Mar 15 2004 +- Add patch that sets up gssapi_mech.conf correctly + +* Fri Mar 12 2004 +- Added the shutting down of the rpc v4 daemons. +- Updated the Red Hat only patch with some init script changes. + +* Thu Mar 11 2004 Bill Nottingham +- rpc_pipefs mounting and aliases are now in modutils; require that + +* Thu Mar 11 2004 +- Updated the gssd patch. + +* Sun Mar 7 2004 +- Added the addition and deletion of rpc_pipefs to /etc/fstab +- Added the addition and deletion of module aliases to /etc/modules.conf + +* Mon Mar 1 2004 +- Removed gssd tarball and old nfsv4 patch. +- Added new nfsv4 patches that include both the + gssd and idmapd daemons +- Added redhat-only v4 patch that reduces the + static librpc.a to only contain gss rpc related + routines (I would rather have gssd use the glibc + rpc routines) +-Changed the gssd svcgssd init scripts to only + start up if SECURE_NFS is set to 'yes' in + /etc/sysconfig/nfs + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Thu Feb 12 2004 Thomas Woerner +- make rpc.lockd, rpc.statd, rpc.mountd and rpc.nfsd pie + +* Wed Jan 28 2004 Steve Dickson +- Added the NFSv4 bits + +* Mon Dec 29 2003 Steve Dickson +- Added the -z flag to nfsstat + +* Wed Dec 24 2003 Steve Dickson +- Fixed lockd port setting in nfs.int script + +* Wed Oct 22 2003 Steve Dickson +- Upgrated to 1.0.6 +- Commented out the acl path for fedora + +* Wed Aug 27 2003 Steve Dickson +- Added the setting of lockd ports via sysclt interface +- Removed queue setting code since its no longer needed + +* Thu Aug 7 2003 Steve Dickson +- Added back the acl patch Taroon b2 + +* Wed Jul 23 2003 Steve Dickson +- Commented out the acl patch (for now) + +* Mon Jul 21 2003 Steve Dickson +- Upgrated to 1.0.5 + +* Wed Jun 18 2003 Steve Dickson +- Added security update +- Fixed the drop-privs.patch which means the chroot +patch could be removed. + +* Mon Jun 9 2003 Steve Dickson +- Defined the differ kinds of debugging avaliable for mountd in +the mountd man page. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Tue Jun 3 2003 Steve Dickson +- Upgraded to 1.0.3 +- Fixed numerous bugs in init scrips +- Added nfsstat overflow patch + +* Thu Jan 23 2003 Tim Powers 1.0.1-2.9 +- rebuild + +* Fri Dec 13 2002 Daniel J Walsh +- change init script to not start rpc.lock if already running + +* Wed Dec 11 2002 Daniel J Walsh +- Moved access code to be after dropping privs + +* Mon Nov 18 2002 Stephen C. Tweedie +- Build with %%configure +- Add nhfsgraph, nhfsnums and nhfsrun to the files list + +* Mon Nov 11 2002 Stephen C. Tweedie +- Don't drop privs until we've bound the notification socket + +* Thu Nov 7 2002 Stephen C. Tweedie +- Ignore SIGPIPE in rpc.mountd + +* Thu Aug 1 2002 Bob Matthews +- Add Sean O'Connell's nfs control tweaks +- to nfs init script. + +* Mon Jul 22 2002 Bob Matthews +- Move to nfs-utils-1.0.1 + +* Mon Feb 18 2002 Bob Matthews +- "service nfs restart" should start services even if currently +- not running (#59469) +- bump version to 0.3.3-4 + +* Wed Oct 3 2001 Bob Matthews +- Move to nfs-utils-0.3.3 +- Make nfsnobody a system account (#54221) + +* Tue Aug 21 2001 Bob Matthews +- if UID 65534 is unassigned, add user nfsnobody (#22685) + +* Mon Aug 20 2001 Bob Matthews +- fix typo in nfs init script which prevented MOUNTD_PORT from working (#52113) + +* Tue Aug 7 2001 Bob Matthews +- nfs init script shouldn't fail if /etc/exports doesn't exist (#46432) + +* Fri Jul 13 2001 Bob Matthews +- Make %%pre useradd consistent with other Red Hat packages. + +* Tue Jul 03 2001 Michael K. Johnson +- Added sh-utils dependency for uname -r in nfs init script + +* Tue Jun 12 2001 Bob Matthews +- make non RH kernel release strings scan correctly in +- nfslock init script (#44186) + +* Mon Jun 11 2001 Bob Matthews +- don't install any rquota pages in _mandir: (#39707, #44119) +- don't try to manipulate rpc.rquotad in init scripts +- unless said program actually exists: (#43340) + +* Tue Apr 10 2001 Preston Brown +- don't translate initscripts for 6.x + +* Tue Apr 10 2001 Michael K. Johnson +- do not start lockd on kernel 2.2.18 or higher (done automatically) + +* Fri Mar 30 2001 Preston Brown +- don't use rquotad from here now; quota package contains a version that + works with 2.4 (#33738) + +* Mon Mar 12 2001 Bob Matthews +- Statd logs at LOG_DAEMON rather than LOG_LOCAL5 +- s/nfs/\$0/ where appropriate in init scripts + +* Tue Mar 6 2001 Jeff Johnson +- Move to nfs-utils-0.3.1 + +* Wed Feb 14 2001 Bob Matthews +- #include patch + +* Mon Feb 12 2001 Bob Matthews +- Really enable netgroups + +* Mon Feb 5 2001 Bernhard Rosenkraenzer +- i18nize initscripts + +* Fri Jan 19 2001 Bob Matthews +- Increased {s,r}blen in rpcmisc.c:makesock to accommodate eepro100 + +* Tue Jan 16 2001 Bob Matthews +- Hackish fix in build section to enable netgroups + +* Wed Jan 3 2001 Bob Matthews +- Fix incorrect file specifications in statd manpage. +- Require gawk 'cause it's used in nfslock init script. + +* Wed Dec 13 2000 Bob Matthews +- Require sed because it's used in nfs init script + +* Tue Dec 12 2000 Bob Matthews +- Don't do a chroot(2) after dropping privs, in statd. + +* Mon Dec 11 2000 Bob Matthews +- NFSv3 if kernel >= 2.2.18, detected in init script + +* Thu Nov 23 2000 Florian La Roche +- update to 0.2.1 + +* Tue Nov 14 2000 Bill Nottingham +- don't start lockd on 2.4 kernels; it's unnecessary + +* Tue Sep 5 2000 Florian La Roche +- more portable fix for mandir + +* Sun Sep 3 2000 Florian La Roche +- update to 0.2-release + +* Fri Sep 1 2000 Florian La Roche +- fix reload script + +* Thu Aug 31 2000 Florian La Roche +- update to 0.2 from CVS +- adjust statd-drop-privs patch +- disable tcp_wrapper support + +* Wed Aug 2 2000 Bill Nottingham +- fix stop priority of nfslock + +* Tue Aug 1 2000 Bill Nottingham +- um, actually *include and apply* the statd-drop-privs patch + +* Mon Jul 24 2000 Bill Nottingham +- fix init script ordering (#14502) + +* Sat Jul 22 2000 Bill Nottingham +- run statd chrooted and as non-root +- add prereqs + +* Tue Jul 18 2000 Trond Eivind Glomsrød +- use "License", not "Copyright" +- use %%{_tmppath} and %%{_mandir} + +* Mon Jul 17 2000 Matt Wilson +- built for next release + +* Mon Jul 17 2000 Matt Wilson +- 0.1.9.1 +- remove patch0, has been integrated upstream + +* Wed Feb 9 2000 Bill Nottingham +- the wonderful thing about triggers, is triggers are wonderful things... + +* Thu Feb 03 2000 Cristian Gafton +- switch to nfs-utils as the base tree +- fix the statfs patch for the new code base +- single package that obsoletes everything we had before (if I am to keep + some traces of my sanity with me...) + +* Mon Jan 17 2000 Preston Brown +- use statfs syscall instead of stat to determinal optimal blksize