* [PATCH RFC 2/3] Add LDAP-free version of libnfsjunct to nfs-utils
2018-01-08 21:49 [PATCH RFC 0/3] Add server-side support for junctions to nfs-utils Chuck Lever
@ 2018-01-08 21:50 ` Chuck Lever
2018-01-08 21:50 ` [PATCH RFC 3/3] Add 'nfsref' command Chuck Lever
2018-01-09 19:21 ` [PATCH RFC 0/3] Add server-side support for junctions to nfs-utils J. Bruce Fields
2 siblings, 0 replies; 12+ messages in thread
From: Chuck Lever @ 2018-01-08 21:50 UTC (permalink / raw)
To: linux-nfs
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@oracle.com>
---
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,
+};
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH RFC 3/3] Add 'nfsref' command
2018-01-08 21:49 [PATCH RFC 0/3] Add server-side support for junctions to nfs-utils Chuck Lever
2018-01-08 21:50 ` [PATCH RFC 2/3] Add LDAP-free version of libnfsjunct " Chuck Lever
@ 2018-01-08 21:50 ` Chuck Lever
2018-01-09 19:21 ` [PATCH RFC 0/3] Add server-side support for junctions to nfs-utils J. Bruce Fields
2 siblings, 0 replies; 12+ messages in thread
From: Chuck Lever @ 2018-01-08 21:50 UTC (permalink / raw)
To: linux-nfs
The 'nfsref' command administers junctions. On an NFS server, it
can create new junctions, remove existing junctions, or display
the contents of junctions.
A man page with more details is included.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
configure.ac | 1
utils/Makefile.am | 4 +
utils/nfsref/Makefile.am | 39 +++++++
utils/nfsref/add.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++
utils/nfsref/lookup.c | 211 ++++++++++++++++++++++++++++++++++++
utils/nfsref/nfsref.c | 188 ++++++++++++++++++++++++++++++++
utils/nfsref/nfsref.h | 47 ++++++++
utils/nfsref/nfsref.man | 180 +++++++++++++++++++++++++++++++
utils/nfsref/remove.c | 145 +++++++++++++++++++++++++
9 files changed, 1086 insertions(+)
create mode 100644 utils/nfsref/Makefile.am
create mode 100644 utils/nfsref/add.c
create mode 100644 utils/nfsref/lookup.c
create mode 100644 utils/nfsref/nfsref.c
create mode 100644 utils/nfsref/nfsref.h
create mode 100644 utils/nfsref/nfsref.man
create mode 100644 utils/nfsref/remove.c
diff --git a/configure.ac b/configure.ac
index 8e7f036..59199f9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -604,6 +604,7 @@ AC_CONFIG_FILES([
utils/mount/Makefile
utils/mountd/Makefile
utils/nfsd/Makefile
+ utils/nfsref/Makefile
utils/nfsstat/Makefile
utils/nfsidmap/Makefile
utils/showmount/Makefile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index c75a5a0..d361aea 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -23,6 +23,10 @@ if CONFIG_NFSDCLTRACK
OPTDIRS += nfsdcltrack
endif
+if CONFIG_JUNCTION
+OPTDIRS += nfsref
+endif
+
SUBDIRS = \
exportfs \
mountd \
diff --git a/utils/nfsref/Makefile.am b/utils/nfsref/Makefile.am
new file mode 100644
index 0000000..2b2bb53
--- /dev/null
+++ b/utils/nfsref/Makefile.am
@@ -0,0 +1,39 @@
+##
+## @file utils/nfsref/Makefile.am
+## @brief Process this file with automake to produce utils/nfsref/Makefile.in
+##
+
+##
+## 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
+##
+
+noinst_HEADERS = nfsref.h
+
+sbin_PROGRAMS = nfsref
+nfsref_SOURCES = add.c lookup.c nfsref.c remove.c
+LDADD = $(LIBXML2) $(LIBCAP) \
+ ../../support/nfs/libnfs.la \
+ ../../support/junction/libjunction.la
+
+man8_MANS = nfsref.man
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = -I. -I../../support/include
+##AM_LDFLAGS = -Wl,--as-needed
diff --git a/utils/nfsref/add.c b/utils/nfsref/add.c
new file mode 100644
index 0000000..d5d0cf8
--- /dev/null
+++ b/utils/nfsref/add.c
@@ -0,0 +1,271 @@
+/**
+ * @file utils/nfsref/add.c
+ * @brief Add junction metadata to a local file system object
+ */
+
+/*
+ * 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/stat.h>
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <uuid/uuid.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Default cache expiration for FSN information
+ */
+#define FSN_DEFAULT_TTL (300)
+
+/**
+ * Display help message for "add" subcommand
+ *
+ * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
+ */
+int
+nfsref_add_help(const char *progname)
+{
+ fprintf(stderr, " \n");
+
+ fprintf(stderr, "Usage: %s [ -t type ] add <junction path> "
+ "<server> <export> [ <server> <export> ... ]\n\n",
+ progname);
+
+ fprintf(stderr, "Add a new junction containing the specified list "
+ "of fileset locations.\n");
+ fprintf(stderr, "<junction path> is the filename of the new junction. "
+ "<server> is the hostname\n");
+ fprintf(stderr, "or IP address of an NFS server where the fileset is "
+ "located. <export> is the\n");
+ fprintf(stderr, "export pathname of the fileset on that server.\n\n");
+
+ fprintf(stderr, "For NFS basic junctions, the location list is stored "
+ "locally in the junction.\n");
+ fprintf(stderr, "For FedFS junctions, the location list is stored "
+ "as new FSN and FSL records\n");
+ fprintf(stderr, "on an NSDB.\n");
+
+ return EXIT_SUCCESS;
+}
+
+/**
+ * Fill in default settings for NFSv4.0 fs_locations4
+ *
+ * @param new NFS location structure to fill in
+ *
+ * See section 5.1.3.2 of the NSDB protocol draft.
+ */
+static void
+nfsref_add_fsloc_defaults(struct nfs_fsloc *new)
+{
+ new->nfl_hostport = 0;
+ new->nfl_flags.nfl_varsub = false;
+ new->nfl_currency = -1;
+ new->nfl_validfor = 0;
+ new->nfl_genflags.nfl_writable = false;
+ new->nfl_genflags.nfl_going = false;
+ new->nfl_genflags.nfl_split = true;
+ new->nfl_transflags.nfl_rdma = true;
+ new->nfl_info.nfl_simul = 0;
+ new->nfl_info.nfl_handle = 0;
+ new->nfl_info.nfl_fileid = 0;
+ new->nfl_info.nfl_writever = 0;
+ new->nfl_info.nfl_change = 0;
+ new->nfl_info.nfl_readdir = 0;
+ new->nfl_info.nfl_readrank = 0;
+ new->nfl_info.nfl_readorder = 0;
+ new->nfl_info.nfl_writerank = 0;
+ new->nfl_info.nfl_writeorder = 0;
+}
+
+/**
+ * Convert a pair of command line arguments to one nfs_fsloc structure
+ *
+ * @param server NUL-terminated C string containing file server hostname
+ * @param rootpath NUL-terminated C string containing POSIX-style export path
+ * @param fsloc OUT: NFS location structure
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_build_fsloc() returns FEDFS_OK, caller must free the
+ * returned fsloc with nfs_free_location().
+ */
+static FedFsStatus
+nfsref_add_build_fsloc(const char *server, const char *rootpath,
+ struct nfs_fsloc **fsloc)
+{
+ struct nfs_fsloc *new;
+ FedFsStatus retval;
+
+ if (server == NULL || rootpath == NULL)
+ return FEDFS_ERR_INVAL;
+
+ xlog(D_GENERAL, "%s: Building fsloc for %s:%s",
+ __func__, server, rootpath);
+
+ new = nfs_new_location();
+ if (new == NULL) {
+ xlog(D_GENERAL, "%s: No memory", __func__);
+ return FEDFS_ERR_SVRFAULT;
+ }
+
+ new->nfl_hostname = strdup(server);
+ if (new->nfl_hostname == NULL) {
+ nfs_free_location(new);
+ xlog(D_GENERAL, "%s: No memory", __func__);
+ return FEDFS_ERR_SVRFAULT;
+ }
+
+ retval = nsdb_posix_to_path_array(rootpath, &new->nfl_rootpath);
+ if (retval != FEDFS_OK) {
+ nfs_free_location(new);
+ return retval;
+ }
+
+ nfsref_add_fsloc_defaults(new);
+ *fsloc = new;
+ return FEDFS_OK;
+}
+
+/**
+ * Convert array of command line arguments to list of nfs_fsloc structures
+ *
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @param fslocs OUT: list of NFS locations
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_build_fsloc_list() returns FEDFS_OK, caller must free the
+ * returned list of fslocs with nfs_free_locations().
+ */
+static FedFsStatus
+nfsref_add_build_fsloc_list(char **argv, int optind, struct nfs_fsloc **fslocs)
+{
+ struct nfs_fsloc *fsloc, *result = NULL;
+ FedFsStatus retval;
+ int i;
+
+ for (i = optind + 2; argv[i] != NULL; i += 2) {
+ retval = nfsref_add_build_fsloc(argv[i], argv[i + 1], &fsloc);
+ if (retval != FEDFS_OK) {
+ nfs_free_locations(result);
+ return retval;
+ }
+ if (result == NULL)
+ result = fsloc;
+ else
+ result->nfl_next = fsloc;
+ }
+ if (result == NULL)
+ return FEDFS_ERR_INVAL;
+
+ *fslocs = result;
+ return FEDFS_OK;
+}
+
+/**
+ * Add NFS locations to a junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @return program exit status
+ */
+static int
+nfsref_add_nfs_basic(const char *junct_path, char **argv, int optind)
+{
+ struct nfs_fsloc *fslocs = NULL;
+ FedFsStatus retval;
+
+ xlog(D_GENERAL, "%s: Adding basic junction to %s",
+ __func__, junct_path);
+
+ retval = nfsref_add_build_fsloc_list(argv, optind, &fslocs);
+ switch (retval) {
+ case FEDFS_OK:
+ break;
+ case FEDFS_ERR_INVAL:
+ xlog(L_ERROR, "Missing arguments");
+ return EXIT_FAILURE;
+ case FEDFS_ERR_SVRFAULT:
+ xlog(L_ERROR, "No memory");
+ return EXIT_FAILURE;
+ default:
+ xlog(L_ERROR, "Failed to add NFS location metadata to %s: %s",
+ junct_path, nsdb_display_fedfsstatus(retval));
+ return EXIT_FAILURE;
+ }
+
+ retval = nfs_add_junction(junct_path, fslocs);
+ nfs_free_locations(fslocs);
+ switch (retval) {
+ case FEDFS_OK:
+ break;
+ case FEDFS_ERR_EXIST:
+ xlog(L_ERROR, "%s already contains junction metadata",
+ junct_path);
+ return EXIT_FAILURE;
+ default:
+ xlog(L_ERROR, "Failed to add NFS location metadata to %s: %s",
+ junct_path, nsdb_display_fedfsstatus(retval));
+ return EXIT_FAILURE;
+ }
+
+ printf("Created junction %s\n", junct_path);
+ return EXIT_SUCCESS;
+}
+
+/**
+ * Add locations to a junction
+ *
+ * @param type type of junction to add
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @return program exit status
+ */
+int
+nfsref_add(enum nfsref_type type, const char *junct_path, char **argv, int optind)
+{
+ if (mkdir(junct_path, 0755) == -1)
+ if (errno != EEXIST) {
+ xlog(L_ERROR, "Failed to create junction object: %m");
+ return EXIT_FAILURE;
+ }
+
+ switch (type) {
+ case NFSREF_TYPE_UNSPECIFIED:
+ case NFSREF_TYPE_NFS_BASIC:
+ return nfsref_add_nfs_basic(junct_path, argv, optind);
+ default:
+ xlog(L_ERROR, "Unrecognized junction type");
+ }
+ return EXIT_FAILURE;
+}
diff --git a/utils/nfsref/lookup.c b/utils/nfsref/lookup.c
new file mode 100644
index 0000000..16fca2e
--- /dev/null
+++ b/utils/nfsref/lookup.c
@@ -0,0 +1,211 @@
+/**
+ * @file utils/nfsref/lookup.c
+ * @brief Examine junction metadata from a local file system object
+ */
+
+/*
+ * 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 <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rpcsvc/nfs_prot.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Display help message for "lookup" subcommand
+ *
+ * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
+ */
+int
+nfsref_lookup_help(const char *progname)
+{
+ fprintf(stderr, " \n");
+
+ fprintf(stderr, "Usage: %s [ -t type ] lookup <junction path>\n\n",
+ progname);
+
+ fprintf(stderr, "Display the contents of the junction at "
+ "<junction path>. For NFS basic\n");
+ fprintf(stderr, "junctions, the local contents of the junction "
+ "are displayed. For FedFS\n");
+ fprintf(stderr, "junctions, FSL records are retrieved from the "
+ "NSDB and displayed.\n");
+
+ return EXIT_SUCCESS;
+}
+
+/**
+ * Convert a boolean value into a displayable string constant
+ *
+ * @param value boolean value
+ * @return NUL-terminated static constant C string
+ */
+static const char *
+nfsref_lookup_display_boolean(_Bool value)
+{
+ return value ? "true" : "false";
+}
+
+/**
+ * Display a single NFS location
+ *
+ * @param fsloc pointer to an NFS location structure
+ */
+static void
+nfsref_lookup_display_nfs_location(struct nfs_fsloc *fsloc)
+{
+ char *rootpath;
+
+ if (nsdb_path_array_to_posix(fsloc->nfl_rootpath, &rootpath) == FEDFS_OK) {
+ printf("%s:%s\n", fsloc->nfl_hostname, rootpath);
+ free(rootpath);
+ } else
+ printf("%s: - Invalid root path -\n", fsloc->nfl_hostname);
+ printf("\n");
+
+ printf("\tNFS port:\t%u\n", fsloc->nfl_hostport);
+ printf("\tValid for:\t%d\n", fsloc->nfl_validfor);
+ printf("\tCurrency:\t%d\n", fsloc->nfl_currency);
+ printf("\tFlags:\t\tvarsub(%s)\n",
+ nfsref_lookup_display_boolean(fsloc->nfl_flags.nfl_varsub));
+
+ printf("\tGenFlags:\twritable(%s), going(%s), split(%s)\n",
+ nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_writable),
+ nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_going),
+ nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_split));
+ printf("\tTransFlags:\trdma(%s)\n",
+ nfsref_lookup_display_boolean(fsloc->nfl_transflags.nfl_rdma));
+
+ printf("\tClass:\t\tsimul(%u), handle(%u), fileid(%u)\n",
+ fsloc->nfl_info.nfl_simul,
+ fsloc->nfl_info.nfl_handle,
+ fsloc->nfl_info.nfl_fileid);
+ printf("\tClass:\t\twritever(%u), change(%u), readdir(%u)\n",
+ fsloc->nfl_info.nfl_writever,
+ fsloc->nfl_info.nfl_change,
+ fsloc->nfl_info.nfl_readdir);
+ printf("\tRead:\t\trank(%u), order(%u)\n",
+ fsloc->nfl_info.nfl_readrank, fsloc->nfl_info.nfl_readorder);
+ printf("\tWrite:\t\trank(%u), order(%u)\n",
+ fsloc->nfl_info.nfl_writerank, fsloc->nfl_info.nfl_writeorder);
+
+ printf("\n");
+}
+
+/**
+ * Display a list of NFS locations
+ *
+ * @param fslocs list of NFS locations to display
+ */
+static void
+nfsref_lookup_display_nfs_locations(struct nfs_fsloc *fslocs)
+{
+ struct nfs_fsloc *fsloc;
+
+ for (fsloc = fslocs; fsloc != NULL; fsloc = fsloc->nfl_next)
+ nfsref_lookup_display_nfs_location(fsloc);
+}
+
+/**
+ * List NFS locations in an nfs-basic junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_lookup_nfs_basic(const char *junct_path)
+{
+ struct nfs_fsloc *fslocs = NULL;
+ FedFsStatus retval;
+
+ xlog(D_GENERAL, "%s: Looking up basic junction in %s",
+ __func__, junct_path);
+
+ retval = nfs_is_junction(junct_path);
+ switch (retval) {
+ case FEDFS_OK:
+ break;
+ case FEDFS_ERR_NOTJUNCT:
+ xlog(L_ERROR, "%s is not an nfs-basic junction", junct_path);
+ return EXIT_FAILURE;
+ default:
+ xlog(L_ERROR, "Failed to access %s: %s",
+ junct_path, nsdb_display_fedfsstatus(retval));
+ return EXIT_FAILURE;
+ }
+
+ retval = nfs_get_locations(junct_path, &fslocs);
+ if (retval != FEDFS_OK) {
+ xlog(L_ERROR, "Failed to access %s: %s",
+ junct_path, nsdb_display_fedfsstatus(retval));
+ return EXIT_FAILURE;
+ }
+
+ nfsref_lookup_display_nfs_locations(fslocs);
+
+ nfs_free_locations(fslocs);
+ return EXIT_SUCCESS;
+}
+
+/**
+ * Resolve either a FedFS or NFS basic junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_lookup_unspecified(const char *junct_path)
+{
+ FedFsStatus retval;
+
+ retval = nfs_is_junction(junct_path);
+ if (retval == FEDFS_OK)
+ return nfsref_lookup_nfs_basic(junct_path);
+ xlog(L_ERROR, "%s is not a junction", junct_path);
+ return EXIT_FAILURE;
+}
+
+/**
+ * Enumerate metadata of a junction
+ *
+ * @param type type of junction to add
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+int
+nfsref_lookup(enum nfsref_type type, const char *junct_path)
+{
+ switch (type) {
+ case NFSREF_TYPE_UNSPECIFIED:
+ return nfsref_lookup_unspecified(junct_path);
+ case NFSREF_TYPE_NFS_BASIC:
+ return nfsref_lookup_nfs_basic(junct_path);
+ default:
+ xlog(L_ERROR, "Unrecognized junction type");
+ }
+ return EXIT_FAILURE;
+}
diff --git a/utils/nfsref/nfsref.c b/utils/nfsref/nfsref.c
new file mode 100644
index 0000000..ff7013e
--- /dev/null
+++ b/utils/nfsref/nfsref.c
@@ -0,0 +1,188 @@
+/**
+ * @file utils/nfsref/nfsref.c
+ * @brief Manage NFS referrals
+ */
+
+/*
+ * 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/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <time.h>
+
+#include <locale.h>
+#include <langinfo.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Short form command line options
+ */
+static const char nfsref_opts[] = "?dt:";
+
+/**
+ * Long form command line options
+ */
+static const struct option nfsref_longopts[] = {
+ { "debug", 0, NULL, 'd', },
+ { "help", 0, NULL, '?', },
+ { "type", 1, NULL, 't', },
+ { NULL, 0, NULL, 0, },
+};
+
+/**
+ * Display program synopsis
+ *
+ * @param progname NUL-terminated C string containing name of program
+ */
+static void
+nfsref_usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [ -t type ] SUBCOMMAND [ ARGUMENTS ]\n\n",
+ progname);
+
+ fprintf(stderr, "SUBCOMMAND is one of:\n");
+ fprintf(stderr, "\tadd Add a new junction\n");
+ fprintf(stderr, "\tremove Remove an existing junction\n");
+ fprintf(stderr, "\tlookup Enumerate a junction\n");
+
+ fprintf(stderr, "\nUse \"%s SUBCOMMAND -?\" for details.\n", progname);
+}
+
+/**
+ * Program entry point
+ *
+ * @param argc count of command line arguments
+ * @param argv array of NUL-terminated C strings containing command line arguments
+ * @return program exit status
+ */
+int
+main(int argc, char **argv)
+{
+ char *progname, *subcommand, *junct_path;
+ enum nfsref_type type;
+ int arg, exit_status;
+ _Bool help;
+
+ (void)setlocale(LC_ALL, "");
+ (void)umask(S_IWGRP | S_IWOTH);
+
+ exit_status = EXIT_FAILURE;
+
+ /* Set the basename */
+ if ((progname = strrchr(argv[0], '/')) != NULL)
+ progname++;
+ else
+ progname = argv[0];
+
+ xlog_stderr(1);
+ xlog_syslog(0);
+ xlog_open(progname);
+
+ if (argc < 2) {
+ nfsref_usage(progname);
+ goto out;
+ }
+
+ help = false;
+ type = NFSREF_TYPE_UNSPECIFIED;
+ while ((arg = getopt_long(argc, argv, nfsref_opts,
+ nfsref_longopts, NULL)) != -1) {
+ switch (arg) {
+ case 'd':
+ xlog_config(D_ALL, 1);
+ break;
+ case 't':
+ if (strcmp(optarg, "nfs-basic") == 0)
+ type = NFSREF_TYPE_NFS_BASIC;
+ else if (strcmp(optarg, "nfs-fedfs") == 0)
+ type = NFSREF_TYPE_NFS_FEDFS;
+ else {
+ xlog(L_ERROR,
+ "Unrecognized junction type: %s",
+ optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case '?':
+ help = true;
+ }
+ }
+
+ if (argc < optind + 1) {
+ nfsref_usage(progname);
+ goto out;
+ }
+
+ if (!help && geteuid() != 0) {
+ xlog(L_ERROR, "Root permission is required");
+ goto out;
+ }
+
+ subcommand = argv[optind];
+ junct_path = argv[optind + 1];
+
+ if (strcasecmp(subcommand, "add") == 0) {
+ if (help) {
+ exit_status = nfsref_add_help(progname);
+ goto out;
+ }
+ if (argc < optind + 3) {
+ xlog(L_ERROR, "Not enough positional parameters");
+ nfsref_usage(progname);
+ goto out;
+ }
+ exit_status = nfsref_add(type, junct_path, argv, optind);
+ if (exit_status == EXIT_SUCCESS)
+ (void)junction_flush_exports_cache();
+ } else if (strcasecmp(subcommand, "remove") == 0) {
+ if (help) {
+ exit_status = nfsref_remove_help(progname);
+ goto out;
+ }
+ exit_status = nfsref_remove(type, junct_path);
+ if (exit_status == EXIT_SUCCESS)
+ (void)junction_flush_exports_cache();
+ } else if (strcasecmp(subcommand, "lookup") == 0) {
+ if (help) {
+ exit_status = nfsref_lookup_help(progname);
+ goto out;
+ }
+ exit_status = nfsref_lookup(type, junct_path);
+ } else {
+ xlog(L_ERROR, "Unrecognized subcommand: %s", subcommand);
+ nfsref_usage(progname);
+ }
+
+out:
+ exit(exit_status);
+}
diff --git a/utils/nfsref/nfsref.h b/utils/nfsref/nfsref.h
new file mode 100644
index 0000000..e9dd9ae
--- /dev/null
+++ b/utils/nfsref/nfsref.h
@@ -0,0 +1,47 @@
+/**
+ * @file src/nfsref/nfsref.h
+ * @brief Declarations and definitions for nfsref command line tool
+ */
+
+/*
+ * Copyright 2011 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-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.
+ *
+ * fedfs-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 fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#ifndef FEDFS_NFSREF_H
+#define FEDFS_NFSREF_H
+
+/**
+ * Junction types supported by the "nfsref" command
+ */
+enum nfsref_type {
+ NFSREF_TYPE_UNSPECIFIED = 1,
+ NFSREF_TYPE_NFS_BASIC,
+ NFSREF_TYPE_NFS_FEDFS
+};
+
+int nfsref_add(enum nfsref_type type, const char *junct_path, char **argv,
+ int optind);
+int nfsref_remove(enum nfsref_type type, const char *junct_path);
+int nfsref_lookup(enum nfsref_type type, const char *junct_path);
+
+int nfsref_add_help(const char *progname);
+int nfsref_remove_help(const char *progname);
+int nfsref_lookup_help(const char *progname);
+
+#endif /* !FEDFS_NFSREF_H */
diff --git a/utils/nfsref/nfsref.man b/utils/nfsref/nfsref.man
new file mode 100644
index 0000000..1261549
--- /dev/null
+++ b/utils/nfsref/nfsref.man
@@ -0,0 +1,180 @@
+.\"@(#)nfsref.8"
+.\"
+.\" @file utils/nfsref/nfsref.man
+.\" @brief man page for nfsref command
+.\"
+
+.\"
+.\" 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
+.\"
+.TH NFSREF 8 "9 Jan 2018"
+.SH NAME
+nfsref \- manage NFS referrals
+.SH SYNOPSIS
+.B nfsref
+.RB [ \-?d ]
+.RB [ \-t
+.IB type ]
+.B add
+.I pathname server export
+.RI [ " server"
+.IR export " ... ]"
+.P
+.B nfsref
+.RB [ \-?d ]
+.RB [ \-t
+.IB type ]
+.B remove
+.I pathname
+.P
+.B nfsref
+.RB [ \-?d ]
+.RB [ \-t
+.IB type ]
+.B lookup
+.I pathname
+.SH INTRODUCTION
+NFS version 4 introduces the concept of
+.I file system referrals
+to NFS.
+A file system referral is like a symbolic link on a file server
+to another file system share, possibly on another file server.
+On an NFS client, a referral behaves like an automounted directory.
+The client, under the server's direction, mounts a new NFS export
+automatically when an application first accesses that directory.
+.P
+Referrals are typically used to construct a single file name space
+across multiple file servers.
+Because file servers control the shape of the name space,
+no client configuration is required,
+and all clients see the same referral information.
+.P
+The Linux NFS server supports NFS version 4 referrals.
+Administrators can specify the
+.B refer=
+export option in
+.I /etc/exports
+to configure a list of exports from which the client can choose.
+See
+.BR exports (5)
+for details.
+.P
+.SH DESCRIPTION
+The
+.BR nfsref (8)
+command is a simple way to get started managing junction metadata.
+Other administrative commands provide richer access to junction information.
+.SS Subcommands
+Valid
+.BR nfsref (8)
+subcommands are:
+.IP "\fBadd\fP"
+Adds junction information to the directory named by
+.IR pathname .
+The named directory must already exist,
+and must not already contain junction information.
+Regular directory contents are obscured to NFS clients by this operation.
+.IP
+A list of one or more file server and export path pairs
+is also specified on the command line.
+When creating an NFS basic junction, this list is
+stored in an extended attribute of the directory.
+.IP
+If junction creation is successful, the
+.BR nfsref (8)
+command flushes the kernel's export cache
+to remove previously cached junction information.
+.IP "\fBremove\fP"
+Removes junction information from the directory named by
+.IR pathname .
+The named directory must exist,
+and must contain junction information.
+Regular directory contents are made visible to NFS clients again by this operation.
+.IP
+If junction deletion is successful, the
+.BR nfsref (8)
+command flushes the kernel's export cache
+to remove previously cached junction information.
+.IP "\fBlookup\fP"
+Displays junction information stored in the directory named by
+.IR pathname .
+The named directory must exist,
+and must contain junction information.
+.IP
+When looking up an NFS basic junction, the junction information
+in the directory is listed on
+.IR stdout .
+.SS Command line options
+.IP "\fB\-d, \-\-debug"
+Enables debugging messages during operation.
+.IP "\fB\-t, \-\-type=\fIjunction-type\fP"
+Specifies the junction type for the operation. Valid values for
+.I junction-type
+are
+.B nfs-basic
+or
+.BR nfs-fedfs .
+.IP
+For the
+.B add
+subcommand, the default value if this option is not specified is
+.BR nfs-basic .
+For the
+.B remove
+and
+.B lookup
+subcommands, the
+.B \-\-type
+option is not required. The
+.BR nfsref (8)
+command operates on whatever junction contents are available.
+.SH EXAMPLES
+Suppose you have two file servers,
+.I top.example.net
+and
+.IR home.example.net .
+You want all your clients to mount
+.I top.example.net:/
+and then see the files under
+.I home.example.net:/
+automatically in
+.IR top:/home .
+.P
+On
+.IR top.example.net ,
+you might issue this command as root:
+.RS
+.sp
+# mkdir /home
+.br
+# nfsref --type=nfs-basic add /home home.example.net /
+.br
+Created junction /home.
+.sp
+.RE
+.SH FILES
+.TP
+.I /etc/exports
+NFS server export table
+.SH "SEE ALSO"
+.BR exports (5)
+.sp
+RFC 5661 for a description of NFS version 4 referrals
+.SH "AUTHOR"
+Chuck Lever <chuck.lever@oracle.com>
diff --git a/utils/nfsref/remove.c b/utils/nfsref/remove.c
new file mode 100644
index 0000000..1a4e371
--- /dev/null
+++ b/utils/nfsref/remove.c
@@ -0,0 +1,145 @@
+/**
+ * @file utils/nfsref/remove.c
+ * @brief Remove junction metadata from a local file system object
+ */
+
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Display help message for "remove" subcommand
+ *
+ * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
+ */
+int
+nfsref_remove_help(const char *progname)
+{
+ fprintf(stderr, " \n");
+
+ fprintf(stderr, "Usage: %s [ -t type ] remove <junction path>\n\n",
+ progname);
+
+ fprintf(stderr, "Remove the junction at <junction path>. For FedFS "
+ "junctions, FSL and FSN\n");
+ fprintf(stderr, "records are removed from the NSDB.\n");
+
+ return EXIT_SUCCESS;
+}
+
+/**
+ * Remove an NFS locations-style junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_remove_nfs_basic(const char *junct_path)
+{
+ int status = EXIT_FAILURE;
+ FedFsStatus retval;
+
+ xlog(D_GENERAL, "%s: Removing FedFS junction from %s",
+ __func__, junct_path);
+
+ retval = nfs_delete_junction(junct_path);
+ switch (retval) {
+ case FEDFS_OK:
+ printf("Removed nfs-basic junction from %s\n", junct_path);
+ status = EXIT_SUCCESS;
+ break;
+ case FEDFS_ERR_NOTJUNCT:
+ xlog(L_ERROR, "%s is not an nfs-basic junction", junct_path);
+ break;
+ default:
+ xlog(L_ERROR, "Failed to delete %s: %s",
+ junct_path, nsdb_display_fedfsstatus(retval));
+ }
+
+ return status;
+}
+
+/**
+ * Remove any NFS junction information
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_remove_unspecified(const char *junct_path)
+{
+ FedFsStatus retval;
+
+ xlog(D_GENERAL, "%s: Removing junction from %s",
+ __func__, junct_path);
+
+ retval = nfs_delete_junction(junct_path);
+ if (retval != FEDFS_OK) {
+ if (retval != FEDFS_ERR_NOTJUNCT)
+ goto out_err;
+ }
+
+ printf("Removed junction from %s\n", junct_path);
+ return EXIT_SUCCESS;
+
+out_err:
+ switch (retval) {
+ case FEDFS_ERR_NOTJUNCT:
+ xlog(L_ERROR, "No junction information found in %s", junct_path);
+ break;
+ default:
+ xlog(L_ERROR, "Failed to delete %s: %s",
+ junct_path, nsdb_display_fedfsstatus(retval));
+ }
+ return EXIT_FAILURE;
+}
+
+/**
+ * Remove an NFS junction
+ *
+ * @param type type of junction to add
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+int
+nfsref_remove(enum nfsref_type type, const char *junct_path)
+{
+ switch (type) {
+ case NFSREF_TYPE_UNSPECIFIED:
+ return nfsref_remove_unspecified(junct_path);
+ case NFSREF_TYPE_NFS_BASIC:
+ return nfsref_remove_nfs_basic(junct_path);
+ default:
+ xlog(L_ERROR, "Unrecognized junction type");
+ }
+ return EXIT_FAILURE;
+}
^ permalink raw reply related [flat|nested] 12+ messages in thread