From 3a0f5263fef6528c2eabba3549da0b5a6b85d8c1 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Jan 16 2012 19:50:51 +0000 Subject: Update to upstream RC release: nfs-utils-1.2.6-rc6 Signed-off-by: Steve Dickson --- diff --git a/nfs-utils-1.2.6-rc4.patch b/nfs-utils-1.2.6-rc4.patch deleted file mode 100644 index 028856c..0000000 --- a/nfs-utils-1.2.6-rc4.patch +++ /dev/null @@ -1,587 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 80fb39d..f101b86 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -265,6 +265,12 @@ if test "$enable_nfsv4" = yes; then - AC_RPCSEC_VERSION - fi - fi -+ -+if test "$enable_nfsv41" = yes; then -+ AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed])) -+ AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h])) -+fi -+ - dnl enable nfsidmap when its support by libnfsidmap - AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"]) - -diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h -index d391e91..dbec5ba 100644 ---- a/support/include/nfs/debug.h -+++ b/support/include/nfs/debug.h -@@ -76,6 +76,9 @@ enum { - #define NFSDBG_CALLBACK 0x0100 - #define NFSDBG_CLIENT 0x0200 - #define NFSDBG_MOUNT 0x0400 -+#define NFSDBG_FSCACHE 0x0800 -+#define NFSDBG_PNFS 0x1000 -+#define NFSDBG_PNFS_LD 0x2000 - #define NFSDBG_ALL 0xFFFF - - #endif /* _NFS_DEBUG_H */ -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index fa0dc6b..3990578 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -256,13 +256,14 @@ conf_parse_line(int trans, char *line, size_t sz) - val++, j++; - if (*val) - i = j; -- section = malloc(i); -+ section = malloc(i+1); - if (!section) { - xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, - (unsigned long)i); - return; - } - strncpy(section, line, i); -+ section[i] = '\0'; - - if (arg) - free(arg); -diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c -index 275a491..444616d 100644 ---- a/tools/rpcdebug/rpcdebug.c -+++ b/tools/rpcdebug/rpcdebug.c -@@ -167,6 +167,9 @@ static struct flagmap { - FLAG(NFS, CALLBACK), - FLAG(NFS, CLIENT), - FLAG(NFS, MOUNT), -+ FLAG(NFS, FSCACHE), -+ FLAG(NFS, PNFS), -+ FLAG(NFS, PNFS_LD), - FLAG(NFS, ALL), - - /* nfsd */ -diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c -index 27ff374..652a7a8 100644 ---- a/utils/blkmapd/device-process.c -+++ b/utils/blkmapd/device-process.c -@@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln - off_t stripe_unit = vol->param.bv_stripe_unit; - /* Check limitations imposed by device-mapper */ - if ((stripe_unit & (stripe_unit - 1)) != 0 -- || stripe_unit < (off_t) (PAGE_SIZE >> 9)) -+ || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9)) - return -EIO; - BLK_READBUF(p, end, 4); - READ32(vol->bv_vol_n); -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 364f247..8853486 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -177,7 +177,7 @@ In this way - .B exportfs - can be used to modify the export options of an already exported directory. - .SS Unexporting Directories --The third synopsis shows how to unexported a currently exported directory. -+The third synopsis shows how to unexport a currently exported directory. - When using - .BR "exportfs -ua" , - all entries listed in -diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man -index 7365a1b..47b73be 100644 ---- a/utils/exportfs/nfsd.man -+++ b/utils/exportfs/nfsd.man -@@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server - .SH DESCRIPTION - The - .B nfsd --filesytem is a special filesystem which provides access to the Linux -+filesystem is a special filesystem which provides access to the Linux - NFS server. The filesystem consists of a single directory which - contains a number of files. These files are actually gateways into - the NFS server. Writing to them can affect the server. Reading from -@@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the - fields, and octal quoting of special characters. - - On writing this, the program will be able to read back a filehandle --for that path as exported to the given client. The filehandles length -+for that path as exported to the given client. The filehandle's length - will be at most the number of bytes given. - - The filehandle will be represented in hex with a leading '\ex'. -@@ -165,7 +165,7 @@ file. The user-space program might then write - .ti +5 - nfsd 127.0.0.1 1057206953 localhost - .br --to indicate that 127.0.0.1 should map to localhost, atleast for now. -+to indicate that 127.0.0.1 should map to localhost, at least for now. - - If the program uses select(2) or poll(2) to discover if it can read - from the -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 19d9114..e80efb4 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic) - } else { - event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); - event_add(&ic->ic_event, NULL); -- fcntl(ic->ic_dirfd, F_SETSIG, 0); - fcntl(ic->ic_dirfd, F_NOTIFY, 0); -+ fcntl(ic->ic_dirfd, F_SETSIG, 0); - if (verbose > 0) - xlog_warn("Opened %s", ic->ic_path); - } -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index ce40933..2ad92d1 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -1561,10 +1561,10 @@ To ensure that the saved mount options are not erased during a remount, - specify either the local mount directory, or the server hostname and - export pathname, but not both, during a remount. For example, - .P --.NF --.TA 2.5i -+.nf -+.ta 8n - mount -o remount,ro /mnt --.FI -+.fi - .P - merges the mount option - .B ro -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 314a806..d52e21a 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) - errno = EOPNOTSUPP; - else if (rpc_createerr.cf_stat == RPC_AUTHERROR) - errno = EACCES; -+ else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) -+ errno = ETIMEDOUT; - else if (rpc_createerr.cf_error.re_errno != 0) - errno = rpc_createerr.cf_error.re_errno; - return 0; -@@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -@@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man -index d8988d2..1cf9296 100644 ---- a/utils/nfsd/nfsd.man -+++ b/utils/nfsd/nfsd.man -@@ -38,7 +38,7 @@ request on all known network addresses. This may change in future - releases of the Linux Kernel. - .TP - .B \-p " or " \-\-port port --specify a diferent port to listen on for NFS requests. By default, -+specify a different port to listen on for NFS requests. By default, - .B rpc.nfsd - will listen on port 2049. - .TP -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index f837b91..037aa79 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man - - sbin_PROGRAMS = nfsidmap - nfsidmap_SOURCES = nfsidmap.c --nfsidmap_LDADD = -lnfsidmap -lkeyutils -+nfsidmap_LDADD = -lnfsidmap -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 2d87381..ce8cf3e 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -9,15 +9,25 @@ - #include - #include - --#include -+#include -+#include "xlog.h" - --/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ -+int verbose = 0; -+char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; - - #define MAX_ID_LEN 11 - #define IDMAP_NAMESZ 128 - #define USER 1 - #define GROUP 0 - -+#define PROCKEYS "/proc/keys" -+#ifndef DEFAULT_KEYRING -+#define DEFAULT_KEYRING "id_resolver" -+#endif -+ -+ -+#define UIDKEYS 0x1 -+#define GIDKEYS 0x2 - - /* - * Find either a user or group id based on the name@domain string -@@ -36,9 +46,15 @@ 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) -+ xlog_err("id_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); -+ if (rc < 0) -+ xlog_err("id_lookup: keyctl_instantiate failed: %m"); -+ } - - return rc; - } -@@ -57,6 +73,7 @@ int name_lookup(char *id, key_serial_t key, int type) - rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); - if (rc != 0) { - rc = -1; -+ xlog_err("name_lookup: nfs4_get_default_domain failed: %m"); - goto out; - } - -@@ -67,39 +84,206 @@ 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) -+ xlog_err("name_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, &name, strlen(name), 0); -- -+ if (rc < 0) -+ xlog_err("name_lookup: keyctl_instantiate failed: %m"); -+ } - 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; -+ -+ xlog_syslog(0); -+ if (keyring == NULL) -+ keyring = DEFAULT_KEYRING; -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ 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; -+} -+/* -+ * Revoke a key -+ */ -+static int key_revoke(char *keystr, int keymask) -+{ -+ FILE *fp; -+ char buf[BUFSIZ], *ptr; -+ key_serial_t key; -+ int mask; -+ -+ xlog_syslog(0); -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") != NULL) -+ continue; -+ -+ mask = 0; -+ if ((ptr = strstr(buf, "uid:")) != NULL) -+ mask = UIDKEYS; -+ else if ((ptr = strstr(buf, "gid:")) != NULL) -+ mask = GIDKEYS; -+ else -+ continue; -+ -+ if ((keymask & mask) == 0) -+ continue; -+ -+ if (strncmp(ptr+4, keystr, strlen(keystr)) != NULL) -+ continue; -+ -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("revoking '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ -+ if (keyctl_revoke(key) < 0) { -+ xlog_err("keyctl_revoke(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ -+ keymask &= ~mask; -+ if (keymask == 0) { -+ fclose(fp); -+ return 0; -+ } -+ } -+ xlog_err("'%s' key was not found.", keystr); -+ fclose(fp); -+ return 1; -+} - - int main(int argc, char **argv) - { - char *arg; - char *value; - char *type; -- int rc = 1; -+ int rc = 1, opt; - int timeout = 600; - key_serial_t key; -+ char *progname, *keystr = NULL; -+ int clearing = 0, keymask = 0; -+ -+ /* Set the basename */ -+ if ((progname = strrchr(argv[0], '/')) != NULL) -+ progname++; -+ else -+ progname = argv[0]; - -- if (argc < 3) -+ xlog_open(progname); -+ -+ while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { -+ switch (opt) { -+ case 'u': -+ keymask = UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'g': -+ keymask = GIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'r': -+ keymask = GIDKEYS|UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'c': -+ clearing++; -+ break; -+ case 'v': -+ verbose++; -+ break; -+ case 't': -+ timeout = atoi(optarg); -+ break; -+ default: -+ xlog_warn(usage, progname); -+ break; -+ } -+ } -+ -+ if (keystr) { -+ rc = key_revoke(keystr, keymask); -+ return rc; -+ } -+ if (clearing) { -+ rc = keyring_clear(DEFAULT_KEYRING); -+ return rc; -+ } -+ -+ xlog_stderr(0); -+ if ((argc - optind) != 2) { -+ xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn(usage, progname); - return 1; -+ } -+ -+ if (verbose) -+ nfs4_set_debug(verbose, NULL); -+ -+ key = strtol(argv[optind++], NULL, 10); - -- arg = malloc(sizeof(char) * strlen(argv[2]) + 1); -- strcpy(arg, argv[2]); -+ arg = strdup(argv[optind]); -+ if (arg == NULL) { -+ xlog_err("strdup failed: %m"); -+ return 1; -+ } - type = strtok(arg, ":"); - value = strtok(NULL, ":"); - -- if (argc == 4) { -- timeout = atoi(argv[3]); -- if (timeout < 0) -- timeout = 0; -+ if (verbose) { -+ xlog_warn("key: %ld type: %s value: %s timeout %ld", -+ key, type, value, timeout); - } - -- key = strtol(argv[1], NULL, 10); -- - if (strcmp(type, "uid") == 0) - rc = id_lookup(value, key, USER); - else if (strcmp(type, "gid") == 0) -@@ -109,7 +293,7 @@ int main(int argc, char **argv) - else if (strcmp(type, "group") == 0) - rc = name_lookup(value, key, GROUP); - -- /* Set timeout to 5 (600 seconds) minutes */ -+ /* Set timeout to 10 (600 seconds) minutes */ - if (rc == 0) - keyctl_set_timeout(key, timeout); - -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 2381908..3a3a523 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -5,6 +5,12 @@ - .TH nfsidmap 5 "1 October 2010" - .SH NAME - nfsidmap \- The NFS idmapper upcall program -+.SH SYNOPSIS -+.B "nfsidmap [-v] [-t timeout] key desc" -+.br -+.B "nfsidmap [-v] [-c]" -+.br -+.B "nfsidmap [-v] [-u|-g|-r user]" - .SH DESCRIPTION - The file - .I /usr/sbin/nfsidmap -@@ -12,11 +18,36 @@ 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. - .I /usr/sbin/nfsidmap --should only be called by request-key, and will perform the translation and -+is called by /sbin/request-key, and will perform the translation and - initialize a key with the resulting information. - .PP --NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this --feature. -+.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. -+.SH OPTIONS -+.TP -+.B -c -+Clear the keyring of all the keys. -+.TP -+.B -g user -+Revoke the gid key of the given user. -+.TP -+.B -r user -+Revoke both the uid and gid key of the given user. -+.TP -+.B -t timeout -+Set the expiration timer, in seconds, on the key. -+The default is 600 seconds (10 mins). -+.TP -+.B -u user -+Revoke the uid key of the given user. -+.TP -+.B -v -+Increases the verbosity of the output to syslog -+(can be specified multiple times). - .SH CONFIGURING - The file - .I /etc/request-key.conf -@@ -25,11 +56,13 @@ will need to be modified so - can properly direct the upcall. The following line should be added before a call - to keyctl negate: - .PP --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d - .PP - This will direct all id_resolver requests to the program --.I /usr/sbin/nfsidmap --The last parameter, 600, defines how many seconds into the future the key will -+.I /usr/sbin/nfsidmap. -+The -+.B -t 600 -+defines how many seconds into the future the key will - expire. This is an optional parameter for - .I /usr/sbin/nfsidmap - and will default to 600 seconds when not specified. -@@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the - generic upcall program. If you would like to use your own program for a uid - lookup then you would edit your request-key.conf so it looks similar to this: - .PP --create id_resolver uid:* * /some/other/program %k %d 600 -+create id_resolver uid:* * /some/other/program %k %d - .br --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap %k %d - .PP - 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. diff --git a/nfs-utils-1.2.6-rc6.patch b/nfs-utils-1.2.6-rc6.patch new file mode 100644 index 0000000..8670a1c --- /dev/null +++ b/nfs-utils-1.2.6-rc6.patch @@ -0,0 +1,1257 @@ +diff --git a/aclocal/ipv6.m4 b/aclocal/ipv6.m4 +index 5ee8fb6..75a8582 100644 +--- a/aclocal/ipv6.m4 ++++ b/aclocal/ipv6.m4 +@@ -2,11 +2,6 @@ dnl Checks for IPv6 support + dnl + AC_DEFUN([AC_IPV6], [ + +- AC_CHECK_DECL([AI_ADDRCONFIG], +- [AC_DEFINE([HAVE_DECL_AI_ADDRCONFIG], 1, +- [Define this to 1 if AI_ADDRCONFIG macro is defined])], , +- [ #include ]) +- + if test "$enable_ipv6" = yes; then + + dnl TI-RPC required for IPv6 +@@ -15,15 +10,11 @@ AC_DEFUN([AC_IPV6], [ + fi + + dnl IPv6-enabled networking functions required for IPv6 +- AC_CHECK_FUNCS([getifaddrs getnameinfo bindresvport_sa], , ++ AC_CHECK_FUNCS([getifaddrs getnameinfo], , + [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) + +- dnl Need to detect presence of IPv6 networking at run time via +- dnl getaddrinfo(3); old versions of glibc do not support ADDRCONFIG +- AC_CHECK_DECL([AI_ADDRCONFIG], , +- [AC_MSG_ERROR([full getaddrinfo(3) implementation needed for IPv6 support])], +- [ #include ]) +- ++ AC_CHECK_LIB([tirpc], [bindresvport_sa], [:], ++ [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) + fi + + ])dnl +diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4 +index 3c962b3..b5ac00f 100644 +--- a/aclocal/libevent.m4 ++++ b/aclocal/libevent.m4 +@@ -2,8 +2,9 @@ dnl Checks for libevent + AC_DEFUN([AC_LIBEVENT], [ + + dnl Check for libevent, but do not add -levent to LIBS +- AC_CHECK_LIB([event], [event_dispatch], [libevent=1], ++ AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent], + [AC_MSG_ERROR([libevent not found.])]) ++ AC_SUBST(LIBEVENT) + + AC_CHECK_HEADERS([event.h], , + [AC_MSG_ERROR([libevent headers not found.])]) +diff --git a/aclocal/libnfsidmap.m4 b/aclocal/libnfsidmap.m4 +index 484b1ec..ae697e8 100644 +--- a/aclocal/libnfsidmap.m4 ++++ b/aclocal/libnfsidmap.m4 +@@ -3,7 +3,7 @@ dnl + AC_DEFUN([AC_LIBNFSIDMAP], [ + + dnl Check for libnfsidmap, but do not add -lnfsidmap to LIBS +- AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [libnfsidmap=1], ++ AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [LIBNFSIDMAP=-lnfsidmap], + [AC_MSG_ERROR([libnfsidmap not found.])]) + + AC_CHECK_HEADERS([nfsidmap.h], , +@@ -14,7 +14,10 @@ AC_DEFUN([AC_LIBNFSIDMAP], [ + [AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1, + [Define to 1 if you have the `nfs4_set_debug' function.])]) + +- dnl only enable nfsidmap when libnfsidmap supports it +- AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid]) ++ dnl nfs4_owner_to_uid() doesn't appear in all versions of libnfsidmap ++ dnl We just need this test to set $ac_cv_lib_nfsidmap_nfs4_owner_to_uid ++ AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [:]) ++ ++ AC_SUBST(LIBNFSIDMAP) + + ])dnl +diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 +index 9f0fde0..19b8361 100644 +--- a/aclocal/libtirpc.m4 ++++ b/aclocal/libtirpc.m4 +@@ -13,8 +13,8 @@ AC_DEFUN([AC_LIBTIRPC], [ + + if test "$enable_tirpc" != "no"; then + +- dnl look for the library; add to LIBS if found +- AC_CHECK_LIB([tirpc], [clnt_tli_create], , ++ 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 +@@ -37,4 +37,15 @@ AC_DEFUN([AC_LIBTIRPC], [ + + 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" ++ else ++ LIBTIRPC="" ++ fi ++ ++ AC_SUBST(LIBTIRPC) ++ + ])dnl +diff --git a/configure.ac b/configure.ac +index 80fb39d..920e8da 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -24,9 +24,8 @@ AC_ARG_WITH(statedir, + statedir=/var/lib/nfs) + AC_SUBST(statedir) + AC_ARG_WITH(statdpath, +- [AC_HELP_STRING([--with-statdpath=/foo @<:@default=/var/lib/nfs@:>@], +- [define statd's state dir as /foo instead of the NFS statedir] +- )], ++ [AC_HELP_STRING([--with-statdpath=/foo], ++ [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])], + statdpath=$withval, + statdpath=$statedir + ) +@@ -249,6 +248,8 @@ AC_CHECK_FUNC([getservbyname], , + + AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"]) + ++AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"]) ++ + if test "$enable_nfsv4" = yes; then + dnl check for libevent libraries and headers + AC_LIBEVENT +@@ -265,6 +266,12 @@ if test "$enable_nfsv4" = yes; then + AC_RPCSEC_VERSION + fi + fi ++ ++if test "$enable_nfsv41" = yes; then ++ AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed])) ++ AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h])) ++fi ++ + dnl enable nfsidmap when its support by libnfsidmap + AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"]) + +@@ -293,6 +300,7 @@ AC_SUBST(LIBSOCKET) + AC_SUBST(LIBCRYPT) + AC_SUBST(LIBBSD) + AC_SUBST(LIBBLKID) ++AC_SUBST(LIBDL) + + if test "$enable_libmount" != no; then + AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed])) +@@ -330,7 +338,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \ + stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \ + sys/param.h sys/socket.h sys/time.h sys/vfs.h \ + syslog.h unistd.h com_err.h et/com_err.h \ +- ifaddrs.h]) ++ ifaddrs.h nfs-plugin.h]) + + dnl ************************************************************* + dnl Checks for typedefs, structures, and compiler characteristics +diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h +index d391e91..dbec5ba 100644 +--- a/support/include/nfs/debug.h ++++ b/support/include/nfs/debug.h +@@ -76,6 +76,9 @@ enum { + #define NFSDBG_CALLBACK 0x0100 + #define NFSDBG_CLIENT 0x0200 + #define NFSDBG_MOUNT 0x0400 ++#define NFSDBG_FSCACHE 0x0800 ++#define NFSDBG_PNFS 0x1000 ++#define NFSDBG_PNFS_LD 0x2000 + #define NFSDBG_ALL 0xFFFF + + #endif /* _NFS_DEBUG_H */ +diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c +index fa0dc6b..3990578 100644 +--- a/support/nfs/conffile.c ++++ b/support/nfs/conffile.c +@@ -256,13 +256,14 @@ conf_parse_line(int trans, char *line, size_t sz) + val++, j++; + if (*val) + i = j; +- section = malloc(i); ++ section = malloc(i+1); + if (!section) { + xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, + (unsigned long)i); + return; + } + strncpy(section, line, i); ++ section[i] = '\0'; + + if (arg) + free(arg); +diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c +index 89fa1a4..fec775f 100644 +--- a/support/nfs/nfsctl.c ++++ b/support/nfs/nfsctl.c +@@ -11,16 +11,22 @@ + #endif + + #include ++#include + #include + #include "nfslib.h" + + /* compatibility hack... */ +-#ifndef __NR_nfsctl ++#if !defined(__NR_nfsctl) && defined(__NR_nfsservctl) + #define __NR_nfsctl __NR_nfsservctl + #endif + + int + nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp) + { ++#ifdef __NR_nfsctl + return syscall (__NR_nfsctl, cmd, argp, resp); ++#else ++ errno = ENOSYS; ++ return -1; ++#endif + } +diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c +index 275a491..444616d 100644 +--- a/tools/rpcdebug/rpcdebug.c ++++ b/tools/rpcdebug/rpcdebug.c +@@ -167,6 +167,9 @@ static struct flagmap { + FLAG(NFS, CALLBACK), + FLAG(NFS, CLIENT), + FLAG(NFS, MOUNT), ++ FLAG(NFS, FSCACHE), ++ FLAG(NFS, PNFS), ++ FLAG(NFS, PNFS_LD), + FLAG(NFS, ALL), + + /* nfsd */ +diff --git a/tools/rpcgen/Makefile.am b/tools/rpcgen/Makefile.am +index 51a2bfa..8a9ec89 100644 +--- a/tools/rpcgen/Makefile.am ++++ b/tools/rpcgen/Makefile.am +@@ -12,6 +12,7 @@ rpcgen_SOURCES = rpc_clntout.c rpc_cout.c rpc_hout.c rpc_main.c \ + rpcgen_CFLAGS=$(CFLAGS_FOR_BUILD) + rpcgen_CPPLAGS=$(CPPFLAGS_FOR_BUILD) + rpcgen_LDFLAGS=$(LDFLAGS_FOR_BUILD) ++rpcgen_LDADD=$(LIBTIRPC) + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c +index 27ff374..652a7a8 100644 +--- a/utils/blkmapd/device-process.c ++++ b/utils/blkmapd/device-process.c +@@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln + off_t stripe_unit = vol->param.bv_stripe_unit; + /* Check limitations imposed by device-mapper */ + if ((stripe_unit & (stripe_unit - 1)) != 0 +- || stripe_unit < (off_t) (PAGE_SIZE >> 9)) ++ || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9)) + return -EIO; + BLK_READBUF(p, end, 4); + READ32(vol->bv_vol_n); +diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man +index 364f247..8853486 100644 +--- a/utils/exportfs/exportfs.man ++++ b/utils/exportfs/exportfs.man +@@ -177,7 +177,7 @@ In this way + .B exportfs + can be used to modify the export options of an already exported directory. + .SS Unexporting Directories +-The third synopsis shows how to unexported a currently exported directory. ++The third synopsis shows how to unexport a currently exported directory. + When using + .BR "exportfs -ua" , + all entries listed in +diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man +index 7365a1b..47b73be 100644 +--- a/utils/exportfs/nfsd.man ++++ b/utils/exportfs/nfsd.man +@@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server + .SH DESCRIPTION + The + .B nfsd +-filesytem is a special filesystem which provides access to the Linux ++filesystem is a special filesystem which provides access to the Linux + NFS server. The filesystem consists of a single directory which + contains a number of files. These files are actually gateways into + the NFS server. Writing to them can affect the server. Reading from +@@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the + fields, and octal quoting of special characters. + + On writing this, the program will be able to read back a filehandle +-for that path as exported to the given client. The filehandles length ++for that path as exported to the given client. The filehandle's length + will be at most the number of bytes given. + + The filehandle will be represented in hex with a leading '\ex'. +@@ -165,7 +165,7 @@ file. The user-space program might then write + .ti +5 + nfsd 127.0.0.1 1057206953 localhost + .br +-to indicate that 127.0.0.1 should map to localhost, atleast for now. ++to indicate that 127.0.0.1 should map to localhost, at least for now. + + If the program uses select(2) or poll(2) to discover if it can read + from the +diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am +index d7888ad..d29e132 100644 +--- a/utils/gssd/Makefile.am ++++ b/utils/gssd/Makefile.am +@@ -40,7 +40,7 @@ gssd_SOURCES = \ + + gssd_LDADD = ../../support/nfs/libnfs.a \ + $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(KRBLIBS) +-gssd_LDFLAGS = $(KRBLDFLAGS) ++gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC) + + gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ + $(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS) +@@ -58,8 +58,8 @@ svcgssd_SOURCES = \ + + svcgssd_LDADD = \ + ../../support/nfs/libnfs.a \ +- $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) -lnfsidmap \ +- $(KRBLIBS) ++ $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(LIBNFSIDMAP) \ ++ $(KRBLIBS) $(LIBTIRPC) + + svcgssd_LDFLAGS = $(KRBLDFLAGS) + +diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c +index 3e695ab..64146d7 100644 +--- a/utils/gssd/context_lucid.c ++++ b/utils/gssd/context_lucid.c +@@ -80,6 +80,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, + uint32_t i; + char *skd, *dkd; + gss_buffer_desc fakeoid; ++ int err; + + /* + * The new Kerberos interface to get the gss context +@@ -138,11 +139,10 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, + dkd = (char *) enc_key.data; + for (i = 0; i < enc_key.length; i++) + dkd[i] = skd[i] ^ 0xf0; +- if (write_lucid_keyblock(&p, end, &enc_key)) { +- free(enc_key.data); +- goto out_err; +- } ++ err = write_lucid_keyblock(&p, end, &enc_key); + free(enc_key.data); ++ if (err) ++ goto out_err; + + if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key)) + goto out_err; +@@ -153,7 +153,6 @@ out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + if (buf->value) free(buf->value); + buf->length = 0; +- if (enc_key.data) free(enc_key.data); + return -1; + } + +diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am +index 4328e41..58b33ec 100644 +--- a/utils/idmapd/Makefile.am ++++ b/utils/idmapd/Makefile.am +@@ -16,7 +16,7 @@ idmapd_SOURCES = \ + nfs_idmap.h \ + queue.h + +-idmapd_LDADD = -levent -lnfsidmap ../../support/nfs/libnfs.a ++idmapd_LDADD = $(LIBEVENT) $(LIBNFSIDMAP) ../../support/nfs/libnfs.a + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c +index 19d9114..e80efb4 100644 +--- a/utils/idmapd/idmapd.c ++++ b/utils/idmapd/idmapd.c +@@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic) + } else { + event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); + event_add(&ic->ic_event, NULL); +- fcntl(ic->ic_dirfd, F_SETSIG, 0); + fcntl(ic->ic_dirfd, F_NOTIFY, 0); ++ fcntl(ic->ic_dirfd, F_SETSIG, 0); + if (verbose > 0) + xlog_warn("Opened %s", ic->ic_path); + } +diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am +index 7bc3e2b..7627854 100644 +--- a/utils/mount/Makefile.am ++++ b/utils/mount/Makefile.am +@@ -24,7 +24,8 @@ EXTRA_DIST += nfsmount.conf + endif + + mount_nfs_LDADD = ../../support/nfs/libnfs.a \ +- ../../support/export/libexport.a ++ ../../support/export/libexport.a \ ++ $(LIBTIRPC) + + mount_nfs_SOURCES = $(mount_common) + +diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c +index e450d79..e8f17a9 100644 +--- a/utils/mount/mount_libmount.c ++++ b/utils/mount/mount_libmount.c +@@ -346,6 +346,21 @@ static int mount_main(struct libmnt_context *cxt, int argc, char **argv) + + if (chk_mountpoint(mount_point)) + goto err; ++ ++ /* ++ * The libmount strictly uses only options from fstab if running in ++ * restricted mode (suid, non-root user). This is done in ++ * mnt_context_prepare_mount() by default. ++ * ++ * We have to read fstab before nfsmount.conf, otherwise the options ++ * from nfsmount.conf will be ignored (overwrited). ++ */ ++ rc = mnt_context_apply_fstab(cxt); ++ if (rc) { ++ nfs_error(_("%s: failed to apply fstab options\n"), progname); ++ goto err; ++ } ++ + /* + * Concatenate mount options from the configuration file + */ +diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man +index ce40933..2ad92d1 100644 +--- a/utils/mount/nfs.man ++++ b/utils/mount/nfs.man +@@ -1561,10 +1561,10 @@ To ensure that the saved mount options are not erased during a remount, + specify either the local mount directory, or the server hostname and + export pathname, but not both, during a remount. For example, + .P +-.NF +-.TA 2.5i ++.nf ++.ta 8n + mount -o remount,ro /mnt +-.FI ++.fi + .P + merges the mount option + .B ro +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index 314a806..d52e21a 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) + errno = EOPNOTSUPP; + else if (rpc_createerr.cf_stat == RPC_AUTHERROR) + errno = EACCES; ++ else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) ++ errno = ETIMEDOUT; + else if (rpc_createerr.cf_error.re_errno != 0) + errno = rpc_createerr.cf_error.re_errno; + return 0; +@@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) + case EHOSTUNREACH: + continue; + default: +- break; ++ goto out; + } + } ++out: + return ret; + } + +@@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) + case EHOSTUNREACH: + continue; + default: +- break; ++ goto out; + } + } ++out: + return ret; + } + +diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am +index eba81fc..7db968b 100644 +--- a/utils/mountd/Makefile.am ++++ b/utils/mountd/Makefile.am +@@ -12,7 +12,7 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \ + mountd_LDADD = ../../support/export/libexport.a \ + ../../support/nfs/libnfs.a \ + ../../support/misc/libmisc.a \ +- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) ++ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) $(LIBTIRPC) + mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ + -I$(top_builddir)/support/include \ + -I$(top_srcdir)/support/export +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index d2ae456..ac9cdbd 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -802,6 +802,229 @@ lookup_export(char *dom, char *path, struct addrinfo *ai) + return found; + } + ++#ifdef HAVE_NFS_PLUGIN_H ++#include ++#include ++ ++/* ++ * Walk through a set of FS locations and build a set of export options. ++ * Returns true if all went to plan; otherwise, false. ++ */ ++static _Bool ++locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations, ++ char *options, size_t remaining, int *ttl) ++{ ++ char *server, *last_path, *rootpath, *ptr; ++ _Bool seen = false; ++ ++ last_path = NULL; ++ rootpath = NULL; ++ server = NULL; ++ ptr = options; ++ *ttl = 0; ++ ++ for (;;) { ++ enum jp_status status; ++ int len; ++ ++ status = ops->jp_get_next_location(locations, &server, ++ &rootpath, ttl); ++ if (status == JP_EMPTY) ++ break; ++ if (status != JP_OK) { ++ xlog(D_GENERAL, "%s: failed to parse location: %s", ++ __func__, ops->jp_error(status)); ++ goto out_false; ++ } ++ xlog(D_GENERAL, "%s: Location: %s:%s", ++ __func__, server, rootpath); ++ ++ if (last_path && strcmp(rootpath, last_path) == 0) { ++ len = snprintf(ptr, remaining, "+%s", server); ++ if (len < 0) { ++ xlog(D_GENERAL, "%s: snprintf: %m", __func__); ++ goto out_false; ++ } ++ if ((size_t)len >= remaining) { ++ xlog(D_GENERAL, "%s: options buffer overflow", __func__); ++ goto out_false; ++ } ++ remaining -= (size_t)len; ++ ptr += len; ++ } else { ++ if (last_path == NULL) ++ len = snprintf(ptr, remaining, "refer=%s@%s", ++ rootpath, server); ++ else ++ len = snprintf(ptr, remaining, ":%s@%s", ++ rootpath, server); ++ if (len < 0) { ++ xlog(D_GENERAL, "%s: snprintf: %m", __func__); ++ goto out_false; ++ } ++ if ((size_t)len >= remaining) { ++ xlog(D_GENERAL, "%s: options buffer overflow", ++ __func__); ++ goto out_false; ++ } ++ remaining -= (size_t)len; ++ ptr += len; ++ last_path = rootpath; ++ } ++ ++ seen = true; ++ free(rootpath); ++ free(server); ++ } ++ ++ xlog(D_CALL, "%s: options='%s', ttl=%d", ++ __func__, options, *ttl); ++ return seen; ++ ++out_false: ++ free(rootpath); ++ free(server); ++ return false; ++} ++ ++/* ++ * Walk through the set of FS locations and build an exportent. ++ * Returns pointer to an exportent if "junction" refers to a junction. ++ * ++ * Returned exportent points to static memory. ++ */ ++static struct exportent *do_locations_to_export(struct jp_ops *ops, ++ nfs_fsloc_set_t locations, const char *junction, ++ char *options, size_t options_len) ++{ ++ struct exportent *exp; ++ int ttl; ++ ++ if (!locations_to_options(ops, locations, options, options_len, &ttl)) ++ return NULL; ++ ++ exp = mkexportent("*", (char *)junction, options); ++ if (exp == NULL) { ++ xlog(L_ERROR, "%s: Failed to construct exportent", __func__); ++ return NULL; ++ } ++ ++ exp->e_uuid = NULL; ++ exp->e_ttl = ttl; ++ return exp; ++} ++ ++/* ++ * Convert set of FS locations to an exportent. Returns pointer to ++ * an exportent if "junction" refers to a junction. ++ * ++ * Returned exportent points to static memory. ++ */ ++static struct exportent *locations_to_export(struct jp_ops *ops, ++ nfs_fsloc_set_t locations, const char *junction) ++{ ++ struct exportent *exp; ++ char *options; ++ ++ options = malloc(BUFSIZ); ++ if (options == NULL) { ++ xlog(D_GENERAL, "%s: failed to allocate options buffer", ++ __func__); ++ return NULL; ++ } ++ options[0] = '\0'; ++ ++ exp = do_locations_to_export(ops, locations, junction, ++ options, BUFSIZ); ++ ++ free(options); ++ return exp; ++} ++ ++/* ++ * Retrieve locations information in "junction" and dump it to the ++ * kernel. Returns pointer to an exportent if "junction" refers ++ * to a junction. ++ * ++ * Returned exportent points to static memory. ++ */ ++static struct exportent *invoke_junction_ops(void *handle, ++ const char *junction) ++{ ++ nfs_fsloc_set_t locations; ++ struct exportent *exp; ++ enum jp_status status; ++ struct jp_ops *ops; ++ char *error; ++ ++ ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops"); ++ error = dlerror(); ++ if (error != NULL) { ++ xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s", ++ __func__, error); ++ return NULL; ++ } ++ if (ops->jp_api_version != JP_API_VERSION) { ++ xlog(D_GENERAL, "%s: unrecognized junction API version: %u", ++ __func__, ops->jp_api_version); ++ return NULL; ++ } ++ ++ status = ops->jp_init(false); ++ if (status != JP_OK) { ++ xlog(D_GENERAL, "%s: failed to resolve %s: %s", ++ __func__, junction, ops->jp_error(status)); ++ return NULL; ++ } ++ ++ status = ops->jp_get_locations(junction, &locations); ++ if (status != JP_OK) { ++ xlog(D_GENERAL, "%s: failed to resolve %s: %s", ++ __func__, junction, ops->jp_error(status)); ++ return NULL; ++ } ++ ++ exp = locations_to_export(ops, locations, junction); ++ ++ ops->jp_put_locations(locations); ++ ops->jp_done(); ++ return exp; ++} ++ ++/* ++ * Load the junction plug-in, then try to resolve "pathname". ++ * Returns pointer to an initialized exportent if "junction" ++ * refers to a junction, or NULL if not. ++ * ++ * Returned exportent points to static memory. ++ */ ++static struct exportent *lookup_junction(const char *pathname) ++{ ++ struct exportent *exp; ++ void *handle; ++ ++ handle = dlopen("libnfsjunct.so", RTLD_NOW); ++ if (handle == NULL) { ++ xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror()); ++ return NULL; ++ } ++ (void)dlerror(); /* Clear any error */ ++ ++ exp = invoke_junction_ops(handle, pathname); ++ ++ /* We could leave it loaded to make junction resolution ++ * faster next time. However, if we want to replace the ++ * library, that would require restarting mountd. */ ++ (void)dlclose(handle); ++ return exp; ++} ++#else /* !HAVE_NFS_PLUGIN_H */ ++static inline struct exportent *lookup_junction(const char *UNUSED(pathname)) ++{ ++ return NULL; ++} ++#endif /* !HAVE_NFS_PLUGIN_H */ ++ + static void nfsd_export(FILE *f) + { + /* requests are: +@@ -854,7 +1077,7 @@ static void nfsd_export(FILE *f) + dump_to_cache(f, dom, path, NULL); + } + } else { +- dump_to_cache(f, dom, path, NULL); ++ dump_to_cache(f, dom, path, lookup_junction(path)); + } + out: + xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); +diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c +index e2add2d..704b7a0 100644 +--- a/utils/mountd/fsloc.c ++++ b/utils/mountd/fsloc.c +@@ -40,12 +40,12 @@ static void replicas_print(struct servers *sp) + { + int i; + if (!sp) { +- xlog(L_NOTICE, "NULL replicas pointer\n"); ++ xlog(L_NOTICE, "NULL replicas pointer"); + return; + } +- xlog(L_NOTICE, "replicas listsize=%i\n", sp->h_num); ++ xlog(L_NOTICE, "replicas listsize=%i", sp->h_num); + for (i=0; ih_num; i++) { +- xlog(L_NOTICE, " %s:%s\n", ++ xlog(L_NOTICE, " %s:%s", + sp->h_mp[i]->h_host, sp->h_mp[i]->h_path); + } + } +@@ -125,13 +125,13 @@ static struct servers *method_list(char *data) + int i, listsize; + struct servers *rv=NULL; + +- xlog(L_NOTICE, "method_list(%s)\n", data); ++ xlog(L_NOTICE, "method_list(%s)", data); + for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++) + ptr++; + list = malloc(listsize * sizeof(char *)); + copy = strdup(data); + if (copy) +- xlog(L_NOTICE, "converted to %s\n", copy); ++ xlog(L_NOTICE, "converted to %s", copy); + if (list && copy) { + ptr = copy; + for (i=0; im_export; + + dupexportent(&eep, &pseudo_root.m_export); +- eep.e_hostname = strdup(curexp->e_hostname); ++ eep.e_hostname = curexp->e_hostname; + strncpy(eep.e_path, path, sizeof(eep.e_path)); + if (strcmp(path, "/") != 0) + eep.e_flags &= ~NFSEXP_FSID; +diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am +index c4c6fb0..1536065 100644 +--- a/utils/nfsd/Makefile.am ++++ b/utils/nfsd/Makefile.am +@@ -8,7 +8,7 @@ KPREFIX = @kprefix@ + sbin_PROGRAMS = nfsd + + nfsd_SOURCES = nfsd.c nfssvc.c +-nfsd_LDADD = ../../support/nfs/libnfs.a ++nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC) + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man +index d8988d2..1cf9296 100644 +--- a/utils/nfsd/nfsd.man ++++ b/utils/nfsd/nfsd.man +@@ -38,7 +38,7 @@ request on all known network addresses. This may change in future + releases of the Linux Kernel. + .TP + .B \-p " or " \-\-port port +-specify a diferent port to listen on for NFS requests. By default, ++specify a different port to listen on for NFS requests. By default, + .B rpc.nfsd + will listen on port 2049. + .TP +diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am +index f837b91..c0675c4 100644 +--- a/utils/nfsidmap/Makefile.am ++++ b/utils/nfsidmap/Makefile.am +@@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man + + sbin_PROGRAMS = nfsidmap + nfsidmap_SOURCES = nfsidmap.c +-nfsidmap_LDADD = -lnfsidmap -lkeyutils ++nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a + + MAINTAINERCLEANFILES = Makefile.in +diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c +index 2d87381..cf11551 100644 +--- a/utils/nfsidmap/nfsidmap.c ++++ b/utils/nfsidmap/nfsidmap.c +@@ -3,21 +3,33 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include + +-#include ++#include ++#include "xlog.h" + +-/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ ++int verbose = 0; ++char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; + + #define MAX_ID_LEN 11 + #define IDMAP_NAMESZ 128 + #define USER 1 + #define GROUP 0 + ++#define PROCKEYS "/proc/keys" ++#ifndef DEFAULT_KEYRING ++#define DEFAULT_KEYRING "id_resolver" ++#endif ++ ++static int keyring_clear(char *keyring); ++ ++#define UIDKEYS 0x1 ++#define GIDKEYS 0x2 + + /* + * Find either a user or group id based on the name@domain string +@@ -36,9 +48,31 @@ 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) ++ xlog_err("id_lookup: %s: failed: %m", ++ (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); + +- if (rc == 0) ++ 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: ++ break; ++ } ++ } ++ if (rc < 0) ++ xlog_err("id_lookup: keyctl_instantiate failed: %m"); ++ } + + return rc; + } +@@ -57,6 +91,7 @@ int name_lookup(char *id, key_serial_t key, int type) + rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); + if (rc != 0) { + rc = -1; ++ xlog_err("name_lookup: nfs4_get_default_domain failed: %m"); + goto out; + } + +@@ -67,39 +102,206 @@ 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) ++ xlog_err("name_lookup: %s: failed: %m", ++ (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); + +- if (rc == 0) ++ if (rc == 0) { + rc = keyctl_instantiate(key, &name, strlen(name), 0); +- ++ if (rc < 0) ++ xlog_err("name_lookup: keyctl_instantiate failed: %m"); ++ } + 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; ++ } ++ ++ 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; ++} ++/* ++ * Revoke a key ++ */ ++static int key_revoke(char *keystr, int keymask) ++{ ++ FILE *fp; ++ char buf[BUFSIZ], *ptr; ++ key_serial_t key; ++ int mask; ++ ++ xlog_syslog(0); ++ ++ if ((fp = fopen(PROCKEYS, "r")) == NULL) { ++ xlog_err("fopen(%s) failed: %m", PROCKEYS); ++ return 1; ++ } ++ ++ while(fgets(buf, BUFSIZ, fp) != NULL) { ++ if (strstr(buf, "keyring") != NULL) ++ continue; ++ ++ mask = 0; ++ if ((ptr = strstr(buf, "uid:")) != NULL) ++ mask = UIDKEYS; ++ else if ((ptr = strstr(buf, "gid:")) != NULL) ++ mask = GIDKEYS; ++ else ++ continue; ++ ++ if ((keymask & mask) == 0) ++ continue; ++ ++ if (strncmp(ptr+4, keystr, strlen(keystr)) != 0) ++ continue; ++ ++ if (verbose) { ++ *(strchr(buf, '\n')) = '\0'; ++ xlog_warn("revoking '%s'", buf); ++ } ++ /* ++ * The key is the first arugment in the string ++ */ ++ *(strchr(buf, ' ')) = '\0'; ++ sscanf(buf, "%x", &key); ++ ++ if (keyctl_revoke(key) < 0) { ++ xlog_err("keyctl_revoke(0x%x) failed: %m", key); ++ fclose(fp); ++ return 1; ++ } ++ ++ keymask &= ~mask; ++ if (keymask == 0) { ++ fclose(fp); ++ return 0; ++ } ++ } ++ xlog_err("'%s' key was not found.", keystr); ++ fclose(fp); ++ return 1; ++} + + int main(int argc, char **argv) + { + char *arg; + char *value; + char *type; +- int rc = 1; ++ int rc = 1, opt; + int timeout = 600; + key_serial_t key; ++ char *progname, *keystr = NULL; ++ int clearing = 0, keymask = 0; ++ ++ /* Set the basename */ ++ if ((progname = strrchr(argv[0], '/')) != NULL) ++ progname++; ++ else ++ progname = argv[0]; + +- if (argc < 3) ++ xlog_open(progname); ++ ++ while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { ++ switch (opt) { ++ case 'u': ++ keymask = UIDKEYS; ++ keystr = strdup(optarg); ++ break; ++ case 'g': ++ keymask = GIDKEYS; ++ keystr = strdup(optarg); ++ break; ++ case 'r': ++ keymask = GIDKEYS|UIDKEYS; ++ keystr = strdup(optarg); ++ break; ++ case 'c': ++ clearing++; ++ break; ++ case 'v': ++ verbose++; ++ break; ++ case 't': ++ timeout = atoi(optarg); ++ break; ++ default: ++ xlog_warn(usage, progname); ++ break; ++ } ++ } ++ ++ if (keystr) { ++ rc = key_revoke(keystr, keymask); ++ return rc; ++ } ++ if (clearing) { ++ xlog_syslog(0); ++ rc = keyring_clear(DEFAULT_KEYRING); ++ return rc; ++ } ++ ++ xlog_stderr(0); ++ if ((argc - optind) != 2) { ++ xlog_err("Bad arg count. Check /etc/request-key.conf"); ++ xlog_warn(usage, progname); + return 1; ++ } ++ ++ if (verbose) ++ nfs4_set_debug(verbose, NULL); ++ ++ key = strtol(argv[optind++], NULL, 10); + +- arg = malloc(sizeof(char) * strlen(argv[2]) + 1); +- strcpy(arg, argv[2]); ++ arg = strdup(argv[optind]); ++ if (arg == NULL) { ++ xlog_err("strdup failed: %m"); ++ return 1; ++ } + type = strtok(arg, ":"); + value = strtok(NULL, ":"); + +- if (argc == 4) { +- timeout = atoi(argv[3]); +- if (timeout < 0) +- timeout = 0; ++ if (verbose) { ++ xlog_warn("key: 0x%lx type: %s value: %s timeout %ld", ++ key, type, value, timeout); + } + +- key = strtol(argv[1], NULL, 10); +- + if (strcmp(type, "uid") == 0) + rc = id_lookup(value, key, USER); + else if (strcmp(type, "gid") == 0) +@@ -109,7 +311,7 @@ int main(int argc, char **argv) + else if (strcmp(type, "group") == 0) + rc = name_lookup(value, key, GROUP); + +- /* Set timeout to 5 (600 seconds) minutes */ ++ /* Set timeout to 10 (600 seconds) minutes */ + if (rc == 0) + keyctl_set_timeout(key, timeout); + +diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man +index 2381908..3a3a523 100644 +--- a/utils/nfsidmap/nfsidmap.man ++++ b/utils/nfsidmap/nfsidmap.man +@@ -5,6 +5,12 @@ + .TH nfsidmap 5 "1 October 2010" + .SH NAME + nfsidmap \- The NFS idmapper upcall program ++.SH SYNOPSIS ++.B "nfsidmap [-v] [-t timeout] key desc" ++.br ++.B "nfsidmap [-v] [-c]" ++.br ++.B "nfsidmap [-v] [-u|-g|-r user]" + .SH DESCRIPTION + The file + .I /usr/sbin/nfsidmap +@@ -12,11 +18,36 @@ 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. + .I /usr/sbin/nfsidmap +-should only be called by request-key, and will perform the translation and ++is called by /sbin/request-key, and will perform the translation and + initialize a key with the resulting information. + .PP +-NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this +-feature. ++.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. ++.SH OPTIONS ++.TP ++.B -c ++Clear the keyring of all the keys. ++.TP ++.B -g user ++Revoke the gid key of the given user. ++.TP ++.B -r user ++Revoke both the uid and gid key of the given user. ++.TP ++.B -t timeout ++Set the expiration timer, in seconds, on the key. ++The default is 600 seconds (10 mins). ++.TP ++.B -u user ++Revoke the uid key of the given user. ++.TP ++.B -v ++Increases the verbosity of the output to syslog ++(can be specified multiple times). + .SH CONFIGURING + The file + .I /etc/request-key.conf +@@ -25,11 +56,13 @@ will need to be modified so + can properly direct the upcall. The following line should be added before a call + to keyctl negate: + .PP +-create id_resolver * * /usr/sbin/nfsidmap %k %d 600 ++create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d + .PP + This will direct all id_resolver requests to the program +-.I /usr/sbin/nfsidmap +-The last parameter, 600, defines how many seconds into the future the key will ++.I /usr/sbin/nfsidmap. ++The ++.B -t 600 ++defines how many seconds into the future the key will + expire. This is an optional parameter for + .I /usr/sbin/nfsidmap + and will default to 600 seconds when not specified. +@@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the + generic upcall program. If you would like to use your own program for a uid + lookup then you would edit your request-key.conf so it looks similar to this: + .PP +-create id_resolver uid:* * /some/other/program %k %d 600 ++create id_resolver uid:* * /some/other/program %k %d + .br +-create id_resolver * * /usr/sbin/nfsidmap %k %d 600 ++create id_resolver * * /usr/sbin/nfsidmap %k %d + .PP + 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. +diff --git a/utils/showmount/Makefile.am b/utils/showmount/Makefile.am +index 077b2c7..4ba5ead 100644 +--- a/utils/showmount/Makefile.am ++++ b/utils/showmount/Makefile.am +@@ -7,7 +7,8 @@ sbin_PROGRAMS = showmount + showmount_SOURCES = showmount.c + showmount_LDADD = ../../support/export/libexport.a \ + ../../support/nfs/libnfs.a \ +- ../../support/misc/libmisc.a ++ ../../support/misc/libmisc.a \ ++ $(LIBTIRPC) + showmount_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ + -I$(top_builddir)/support/export + +diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am +index 1744791..dc2bfc4 100644 +--- a/utils/statd/Makefile.am ++++ b/utils/statd/Makefile.am +@@ -15,10 +15,10 @@ BUILT_SOURCES = $(GENFILES) + statd_LDADD = ../../support/nsm/libnsm.a \ + ../../support/nfs/libnfs.a \ + ../../support/misc/libmisc.a \ +- $(LIBWRAP) $(LIBNSL) $(LIBCAP) ++ $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC) + sm_notify_LDADD = ../../support/nsm/libnsm.a \ + ../../support/nfs/libnfs.a \ +- $(LIBNSL) $(LIBCAP) ++ $(LIBNSL) $(LIBCAP) $(LIBTIRPC) + + EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c + diff --git a/nfs-utils.spec b/nfs-utils.spec index a8e6c24..070741b 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.2.5 -Release: 10%{?dist} +Release: 11%{?dist} Epoch: 1 # group all 32bit related archs @@ -28,7 +28,7 @@ Source51: nfs-server.preconfig Source52: nfs-server.postconfig %define nfs_configs %{SOURCE50} %{SOURCE51} %{SOURCE52} -Patch001: nfs-utils-1.2.6-rc5.patch +Patch001: nfs-utils-1.2.6-rc6.patch Patch002: nfs-utils-1.2.4-mountshortcut.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch @@ -277,6 +277,9 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Mon Jan 16 2012 Steve Dickson 1.2.5-11 +- Update to upstream RC release: nfs-utils-1.2.6-rc6 + * 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)