[PATCH RFC 2/3] Add LDAP-free version of libnfsjunct to nfs-utils

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



libnfsjunct is a dynamic library that mountd can load to enable
the Linux NFS server to support junctions. This patch moves the
non-LDAP parts of libnfsjunct into nfs-utils. This enables mountd to
continue to recognize and support NFS basic junctions.

mountd works fine whether or not there is a libnfsjunct installed
on the local system, just as it did before. Without libnfsjunct,
junctions on the NFS server appear to NFS clients like weird
directories.

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---
 support/include/Makefile.am   |    1 
 support/include/nfs-plugin.h  |  101 ++++++++++++
 support/junction/Makefile.am  |    6 +
 support/junction/nfs-plugin.c |  350 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 458 insertions(+)
 create mode 100644 support/include/nfs-plugin.h
 create mode 100644 support/junction/nfs-plugin.c

diff --git a/support/include/Makefile.am b/support/include/Makefile.am
index 11cb162..a207d21 100644
--- a/support/include/Makefile.am
+++ b/support/include/Makefile.am
@@ -9,6 +9,7 @@ noinst_HEADERS = \
 	ha-callout.h \
 	junction.h \
 	misc.h \
+	nfs-plugin.h \
 	nfs_mntent.h \
 	nfs_paths.h \
 	nfslib.h \
diff --git a/support/include/nfs-plugin.h b/support/include/nfs-plugin.h
new file mode 100644
index 0000000..33e63f3
--- /dev/null
+++ b/support/include/nfs-plugin.h
@@ -0,0 +1,101 @@
+/*
+ * @file support/include/nfs-plugin.h
+ * @brief Definition of NFS junction plug-in API
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+/*
+ * The purpose of this API is to provide an opaque mechanism for
+ * the NFS mountd daemon to resolve NFS basic and FedFS junctions.
+ * This interface is therefore quite specific to NFS.
+ */
+
+#ifndef NFS_PLUGIN_H
+#define NFS_PLUGIN_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/**
+ * Current version of API
+ */
+#define JP_API_VERSION		(1)
+
+/**
+ * NFS plug-in library soname; passed to dlopen(3)
+ */
+#define JP_NFSPLUGIN_SONAME	"libnfsjunct.so.0"
+
+/**
+ * A set of NFS FS locations
+ */
+struct nfs_fsloc_set;
+typedef struct nfs_fsloc_set	 *nfs_fsloc_set_t;
+
+/**
+ * Junction operation status codes
+ */
+enum jp_status {
+	JP_OK			=  0,
+	JP_INVAL		= -1,
+	JP_ACCESS		= -2,
+	JP_EXIST		= -3,
+	JP_TYPE_NOT_SUPP	= -4,
+	JP_OP_NOT_SUPP		= -5,
+	JP_ISJUNCTION		= -6,
+	JP_NOTJUNCTION		= -7,
+	JP_NSDBLOCAL		= -8,
+	JP_NSDBREMOTE		= -9,
+	JP_MEMORY		= -10,
+	JP_SYSTEM		= -11,
+	JP_PARSE		= -1000,
+	JP_EMPTY		= -1001,
+};
+
+/**
+ * Vector of methods provided by a junction plug-in
+ */
+struct jp_ops {
+	unsigned int	  jp_api_version;
+
+	enum jp_status	  (*jp_init)(_Bool want_debugging);
+	void		  (*jp_done)(void);
+
+	const char *	  (*jp_error)(enum jp_status status);
+	void		  (*jp_put_locations)(nfs_fsloc_set_t locset);
+	enum jp_status	  (*jp_get_locations)(const char *junct_path,
+					nfs_fsloc_set_t *locset);
+	void		  (*jp_rewind_locations)(nfs_fsloc_set_t locset);
+	enum jp_status	  (*jp_get_next_location)(nfs_fsloc_set_t locset,
+					char **hostname, char **export_path,
+					int *ttl);
+};
+
+/**
+ * Load this symbol to get access to the junction API
+ */
+extern struct jp_ops	  nfs_junction_ops;
+
+__END_DECLS
+
+#endif	/* !NFS_PLUGIN_H */
diff --git a/support/junction/Makefile.am b/support/junction/Makefile.am
index 97e7426..9494f55 100644
--- a/support/junction/Makefile.am
+++ b/support/junction/Makefile.am
@@ -29,6 +29,12 @@ noinst_LTLIBRARIES	= libjunction.la
 libjunction_la_SOURCES	= display.c export-cache.c junction.c \
 			  locations.c nfs.c path.c xml.c
 
+lib_LTLIBRARIES		= libnfsjunct.la
+libnfsjunct_la_SOURCES	= nfs-plugin.c
+libnfsjunct_la_LIBADD	= $(LIBXML2) \
+			  ../../support/nfs/libnfs.la \
+			  libjunction.la
+
 MAINTAINERCLEANFILES	= Makefile.in
 
 AM_CPPFLAGS		= -I. -I../include -I/usr/include/libxml2
diff --git a/support/junction/nfs-plugin.c b/support/junction/nfs-plugin.c
new file mode 100644
index 0000000..61039ca
--- /dev/null
+++ b/support/junction/nfs-plugin.c
@@ -0,0 +1,350 @@
+/**
+ * @file support/junction/nfs-plugin.c
+ * @brief DLL to resolve junction information
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <libxml/parser.h>
+
+#include "fedfs_admin.h"
+#include "nfs-plugin.h"
+#include "junction.h"
+
+#define VERSION			"0.12.0"
+#define FEDFS_NFS_BASIC_TTL	(300)
+
+struct nfs_fsloc_set {
+	int			  ns_ttl;
+	struct nfs_fsloc	 *ns_current;
+	struct nfs_fsloc	 *ns_list;
+};
+
+static _Bool debug = false;
+
+/**
+ * Write a debugging message to stderr
+ *
+ * @param fmt NUL-terminated C string containing output format specification
+ *
+ * NB:	Caller may have already opened syslog for her own use.  We can't
+ *	hijack it here, so using xlog() is right out.  Thus output is
+ *	directed to stderr via fprintf(3).
+ */
+static void
+nfs_jp_debug(const char *fmt, ...)
+{
+	va_list args;
+
+	if (!debug)
+		return;
+
+	va_start(args, fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+}
+
+/**
+ * Perform any plug-in startup processing
+ *
+ * @param want_debugging true if caller wants to enable debugging output
+ * @return a junction status code
+ */
+static enum jp_status
+nfs_jp_init(_Bool want_debugging)
+{
+	debug = want_debugging;
+	nfs_jp_debug("%s: Junction plug-in version " VERSION "\n", __func__);
+	xmlInitParser();
+	return JP_OK;
+}
+
+/**
+ * Perform any plug-in shutdown processing
+ *
+ * Nothing to be done for NFS junctions.
+ */
+static void
+nfs_jp_done(void)
+{
+	nfs_jp_debug("%s: Finishing\n", __func__);
+	xmlCleanupParser();
+	return;
+}
+
+/**
+ * Given an status code, return a pointer to a static error message
+ *
+ * @param status a junction plug-in status code
+ * @return a static NUL-terminated string
+ */
+static const char *
+nfs_jp_error(enum jp_status status)
+{
+	static char buf[128];
+
+	switch (status) {
+	case JP_OK:
+		return "Success";
+	case JP_INVAL:
+		return "Invalid parameter";
+	case JP_ACCESS:
+		return "Permission denied";
+	case JP_EXIST:
+		return "Object cannot be made into a junction";
+	case JP_TYPE_NOT_SUPP:
+		return "Junction type not supported";
+	case JP_OP_NOT_SUPP:
+		return "Junction method not supported";
+	case JP_ISJUNCTION:
+		return "Object is a junction";
+	case JP_NOTJUNCTION:
+		return "Object is not a junction";
+	case JP_NSDBLOCAL:
+		return "A local NSDB configuration error occurred";
+	case JP_NSDBREMOTE:
+		return "An error occurred on the NSDB";
+	case JP_MEMORY:
+		return "Memory allocation failure";
+	case JP_SYSTEM:
+		snprintf(buf, sizeof(buf), "System error (%d): %s",
+				status, strerror(errno));
+		return buf;
+	case JP_PARSE:
+		return "Failed to parse locations data";
+	case JP_EMPTY:
+		return "No more locations in location set";
+	}
+
+	snprintf(buf, sizeof(buf), "Unknown error (%d)", status);
+	return buf;
+}
+
+/**
+ * Release a set of NFS locations
+ *
+ * @param locset set of NFS locations to release
+ */
+static void
+nfs_jp_put_locations(nfs_fsloc_set_t locset)
+{
+	if (locset == NULL) {
+		nfs_jp_debug("%s: Invalid parameters\n", __func__);
+		return;
+	}
+
+	nfs_jp_debug("%s: Freeing location set %p, ns_list=%p\n",
+		__func__, locset, locset->ns_list);
+	nfs_free_locations(locset->ns_list);
+	free(locset);
+}
+
+/**
+ * Internal function to allocate a set of NFS locations
+ *
+ * @return dynamically allocated nfs_fsloc_set_t object
+ *
+ * If return value is non-NULL, caller must free it with
+ * nfs_jp_put_locations().
+ */
+__attribute_malloc__
+static nfs_fsloc_set_t
+nfs_jp_alloc_locations(void)
+{
+	return calloc(1, sizeof(struct nfs_fsloc_set));
+}
+
+/**
+ * Internal function to rewind a set of locations
+ *
+ * @param locset set of NFS locations to rewind
+ */
+static void
+nfs_jp_do_rewind_locations(nfs_fsloc_set_t locset)
+{
+	locset->ns_current = locset->ns_list;
+}
+
+/**
+ * Resolve NFS basic junction information into a set of NFS locations
+ *
+ * @param junct_path NUL-terminated C string containing POSIX path of junction
+ * @param locset OUT set of NFS locations
+ * @return a junction status code
+ *
+ * If this entry point returns JP_OK, the caller must free the returned
+ * set of locations by calling the jp_put_locations entry point.
+ */
+static enum jp_status
+nfs_jp_get_basic(const char *junct_path, nfs_fsloc_set_t *locset)
+{
+	nfs_fsloc_set_t new;
+	FedFsStatus retval;
+
+	new = nfs_jp_alloc_locations();
+	if (new == NULL) {
+		nfs_jp_debug("%s: No memory\n", __func__);
+		return JP_MEMORY;
+	}
+
+	retval = nfs_get_locations(junct_path, &new->ns_list);
+	if (retval != FEDFS_OK) {
+		nfs_jp_debug("%s: Failed to get locations: %s\n",
+			__func__, nsdb_display_fedfsstatus(retval));
+		nfs_jp_put_locations(new);
+		return JP_PARSE;
+	}
+
+	nfs_jp_debug("%s: Returning location set %p\n", __func__, new);
+	nfs_jp_do_rewind_locations(new);
+	new->ns_ttl = FEDFS_NFS_BASIC_TTL;
+	*locset = new;
+	return JP_OK;
+}
+
+/**
+ * Resolve junction information into a set of NFS locations
+ *
+ * @param junct_path NUL-terminated C string containing POSIX path of junction
+ * @param locset OUT set of NFS locations
+ * @return a junction status code
+ *
+ * If this entry point returns JP_OK, the caller must free the returned
+ * set of locations by calling the jp_put_locations entry point.
+ */
+static enum jp_status
+nfs_jp_get_locations(const char *junct_path, nfs_fsloc_set_t *locset)
+{
+	FedFsStatus retval;
+
+	if (junct_path == NULL || locset == NULL) {
+		nfs_jp_debug("%s: Invalid parameters\n", __func__);
+		return JP_INVAL;
+	}
+	nfs_jp_debug("%s: %s\n", __func__, junct_path);
+
+	retval = nfs_is_junction(junct_path);
+	if (retval == FEDFS_OK)
+		return nfs_jp_get_basic(junct_path, locset);
+
+	nfs_jp_debug("%s: Not a junction\n", __func__);
+	return JP_NOTJUNCTION;
+}
+
+/**
+ * Reset the current location to the first location in the list
+ *
+ * @param locset set of NFS locations
+ */
+static void
+nfs_jp_rewind_locations(nfs_fsloc_set_t locset)
+{
+	if (locset == NULL) {
+		nfs_jp_debug("%s: Invalid parameters\n", __func__);
+		return;
+	}
+
+	nfs_jp_debug("%s: Rewinding %p\n", __func__, locset);
+	nfs_jp_do_rewind_locations(locset);
+}
+
+/**
+ * Get the fileserver hostname and export path from the next location in the set
+ *
+ * @param locset set of NFS locations
+ * @param hostname OUT NUL-terminated C string containing hostname of fileserver
+ * @param export_path OUT NUL-terminated C string containing export path
+ * @param ttl OUT cache time-to-live, in seconds
+ * @return a junction status code
+ *
+ * If this entry point returns JP_OK, the caller must free the hostname
+ * and export_path strings with free(3).
+ */
+static enum jp_status
+nfs_jp_get_next_location(nfs_fsloc_set_t locset,
+		char **hostname, char **export_path, int *ttl)
+{
+	char *hostname_tmp, *export_path_tmp;
+	struct nfs_fsloc *fsloc;
+
+	if (locset == NULL || hostname == NULL ||
+	    export_path == NULL || ttl == NULL) {
+		nfs_jp_debug("%s: Invalid parameters\n", __func__);
+		return JP_INVAL;
+	}
+	nfs_jp_debug("%s: locset=%p, ns_current=%p, ns_list=%p\n",
+		__func__, locset, locset->ns_current, locset->ns_list);
+
+	if (locset->ns_current == NULL) {
+		nfs_jp_debug("%s: No locations\n", __func__);
+		return JP_EMPTY;
+	}
+	fsloc = locset->ns_current;
+
+	hostname_tmp = strdup(fsloc->nfl_hostname);
+	if (hostname_tmp == NULL) {
+		nfs_jp_debug("%s: No memory\n", __func__);
+		return JP_MEMORY;
+	}
+
+	if (nsdb_path_array_to_posix(fsloc->nfl_rootpath,
+					&export_path_tmp) != FEDFS_OK) {
+		free(hostname_tmp);
+		nfs_jp_debug("%s: Failed to parse\n", __func__);
+		return JP_PARSE;
+	}
+
+	nfs_jp_debug("%s: Success; hostname=%s path=%s\n",
+		__func__, hostname_tmp, export_path_tmp);
+	*hostname = hostname_tmp;
+	*export_path = export_path_tmp;
+	*ttl = locset->ns_ttl;
+	locset->ns_current = locset->ns_current->nfl_next;
+	return JP_OK;
+}
+
+/**
+ * Vector of methods provided by this plug-in
+ */
+struct jp_ops nfs_junction_ops = {
+	.jp_api_version		= JP_API_VERSION,
+	.jp_init		= nfs_jp_init,
+	.jp_done		= nfs_jp_done,
+	.jp_error		= nfs_jp_error,
+	.jp_put_locations	= nfs_jp_put_locations,
+	.jp_get_locations	= nfs_jp_get_locations,
+	.jp_rewind_locations	= nfs_jp_rewind_locations,
+	.jp_get_next_location	= nfs_jp_get_next_location,
+};

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux