diff --git a/.gitignore b/.gitignore
index 468a533..10c43a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ Doxygen/
 src/fedfsd/fedfsd
 src/resolve-junction/resolve-junction
 src/nsdbparams/nsdbparams
+src/nfsref/nfsref
 src/mount/mount.fedfs
 src/mount/fedfs-map-nfs4
 libadmin.a
diff --git a/INSTALL b/INSTALL
index 417c34a..186678d 100644
--- a/INSTALL
+++ b/INSTALL
@@ -125,6 +125,8 @@ FedFS file server
 
   o Install mountd with patches to resolve junctions
 
+  o Install the nfsref program
+
   o Set up a fedfs user ID and group ID
 
   o Create /var/lib/fedfs and set its user and group to the fedfs
diff --git a/configure.ac b/configure.ac
index a5afb12..bbe3f19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -170,6 +170,7 @@ AC_CONFIG_FILES([Makefile
                  src/libsi/Makefile
                  src/libxlog/Makefile
                  src/mount/Makefile
+                 src/nfsref/Makefile
                  src/nsdbc/Makefile
                  src/nsdbparams/Makefile
                  src/resolve-junction/Makefile])
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index c9ddfe8..30016ce 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -37,7 +37,7 @@ NSDB_CLIENT_CMDS	= nsdb-create-fsl.8 nsdb-create-fsn.8 \
 			  nsdb-delete-nsdb.8
 
 dist_man7_MANS		= fedfs.7
-dist_man8_MANS		= rpc.fedfsd.8 mount.fedfs.8 fedfs-map-nfs4.8 \
+dist_man8_MANS		= rpc.fedfsd.8 mount.fedfs.8 fedfs-map-nfs4.8 nfsref.8 \
 			  nsdbparams.8 $(FEDFS_CLIENT_CMDS) $(NSDB_CLIENT_CMDS)
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
diff --git a/doc/man/nfsref.8 b/doc/man/nfsref.8
new file mode 100644
index 0000000..ed70366
--- /dev/null
+++ b/doc/man/nfsref.8
@@ -0,0 +1,283 @@
+.\"@(#)nfsref.8"
+.\"
+.\" @file doc/man/nfsref.8
+.\" @brief man page for nfsref command
+.\"
+
+.\"
+.\" 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
+.\"
+.TH NFSREF 8 "@publication-date@"
+.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 server-side symbolic link
+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
+The
+.BR nfsref (8)
+command provides an alternate way to configure NFS referrals.
+This command stores referral information
+as metadata within a leaf directory in an exported file system.
+The metadata it stores can contain one of two types of information:
+.IP "\fIA list of Fileset Locations\fP"
+A set of server name and export path pairs which are returned
+verbatim to clients during an NFS referral event.
+This is known as an
+.IR "NFS basic junction" .
+.IP "\fIA Fileset Name\fP"
+The name of an LDAP record which contains information to return
+to clients during an NFS referral event.
+This is known as a
+.IR "FedFS junction" .
+.P
+A directory can hold either an NFS basic junction or a FedFS junction,
+but not both.
+When a directory acts as a junction, its regular contents remain,
+but are no longer visible to NFS clients.
+.P
+By storing the location information in an LDAP directory,
+FedFS junctions on multiple file servers can refer to
+the same copy of location information.
+This common locations metadata can be updated
+via a single administrative operation,
+altering the file name space consistently across all servers.
+The
+.BR fedfs (7)
+man page has more information.
+.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
+When creating a FedFS junction, FedFS records containing the
+file server and export path pairs are created on an LDAP server,
+and a pointer to the new FedFS records is
+stored in an extended attribute of the directory.
+Fresh FSN and FSL UUIDs are generated during this operation.
+.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
+When removing a FedFS junction,
+existing FedFS records remain on the LDAP server.
+They can be removed by other means if it is known
+that no other junction refers to these records.
+.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 .
+When looking up a FedFS junction, junction information is
+retrieved from the LDAP server listed in the junction
+and listed on
+.IR stdout .
+.P
+When creating a new FedFS junction, the
+.BR nfsref (8)
+command reads the following environment variables:
+.IP "\fBFEDFS_NSDB_HOST\fP"
+Specifies the hostname of the LDAP server where new FedFS records
+should reside.  If this variable is not set, the
+.BR nfsref (8)
+command fails.
+The LDAP server specified by this variable
+must be registered with the local NSDB connection
+parameter database before the
+.BR nfsref (8)
+command can communicate with it.  See
+.BR nsdbparams (8)
+for more information.
+.IP "\fBFEDFS_NSDB_PORT\fP"
+Specifies the IP port of the LDAP server where new FedFS records
+should reside.  The default value if this variable is not set is 389.
+.IP "\fBFEDFS_NSDB_NCE\fP"
+Specifies the distinguished name of the NSDB Container Entry
+under which new FedFS records should reside.
+If this variable is not set, the local NSDB connection parameter
+database is searched for a default NCE for the hostname specified by
+.BR FEDFS_NSDB_HOST .
+If neither of these is specified, the
+.BR nfsref (8)
+command fails.
+.IP "\fBFEDFS_NSDB_ADMIN\fP"
+Specifies a distinguished name of an entity used to bind
+to the LDAP server where new FedFS records should reside.
+If this variable is not set, the local NSDB connection parameter
+database is searched for a default bind DN for the hostname
+specified by
+.BR FEDFS_NSDB_HOST .
+If neither of these is specified, or if this entity does not have
+permission to modify the LDAP server's DIT, the
+.BR nfsref (8)
+command fails.
+.IP "\fBFEDFS_NSDB_PASSWD\fP"
+Specifies the password used for simple authentication
+to the LDAP server where new FedFS records should reside.
+If this variable is not set, the
+.BR nfsref (8)
+command asks for a password on
+.IR stdin .
+Standard password blanking techniques are used to obscure the
+password on the user's terminal.
+.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 fedfs (7),
+.BR nsdbparams (8),
+.BR exports (5)
+.sp
+RFC 3530 for a description of NFS version 4 referrals
+.sp
+RFC 5716 for FedFS requirements and overview
+.SH COLOPHON
+This page is part of the fedfs-utils package.
+A description of the project and information about reporting bugs
+can be found at
+.IR http://oss.oracle.com/projects/fedfs-utils .
+.SH "AUTHOR"
+Chuck Lever <chuck.lever@oracle.com>
diff --git a/src/Makefile.am b/src/Makefile.am
index f4ba864..fcb84e6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,8 +25,8 @@
 
 SUBDIRS			= include libxlog libadmin libnsdb libjunction \
 			  libparser libsi \
-			  fedfsc fedfsd nsdbc nsdbparams resolve-junction \
-			  mount
+			  fedfsc fedfsd mount nfsref nsdbc nsdbparams \
+			  resolve-junction
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
 DISTCLEANFILES		= Makefile.in
diff --git a/src/nfsref/Makefile.am b/src/nfsref/Makefile.am
new file mode 100644
index 0000000..284d4b4
--- /dev/null
+++ b/src/nfsref/Makefile.am
@@ -0,0 +1,41 @@
+##
+## @file src/nfsref/Makefile.am
+## @brief Process this file with automake to produce src/nfsref/Makefile.in
+##
+
+##
+## 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
+##
+
+noinst_HEADERS		= nfsref.h
+sbin_PROGRAMS		= nfsref
+nfsref_SOURCES		= add.c lookup.c nfsref.c remove.c
+LDADD			= $(LIBLDAP) $(LIBLBER) $(LIBXML2) \
+			  $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) \
+			  $(top_builddir)/src/libnsdb/libnsdb.la \
+			  $(top_builddir)/src/libxlog/libxlog.la \
+			  $(top_builddir)/src/libjunction/libjunction.la
+
+CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
+DISTCLEANFILES		= Makefile.in
+
+AM_CFLAGS		= -ggdb -fstrict-aliasing -fPIE \
+			  -Wall -Wextra -pedantic -Wformat=2 \
+			  -Wstrict-aliasing=2 -Wp,-D_FORTIFY_SOURCE=2
+AM_CPPFLAGS		= -I. -I$(top_srcdir)/src/include
diff --git a/src/nfsref/add.c b/src/nfsref/add.c
new file mode 100644
index 0000000..9b292f5
--- /dev/null
+++ b/src/nfsref/add.c
@@ -0,0 +1,620 @@
+/**
+ * @file src/nfsref/add.c
+ * @brief Add junction metadata to a local file system object
+ */
+
+/*
+ * 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
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <uuid/uuid.h>
+
+#include "fedfs.h"
+#include "junction.h"
+#include "nsdb.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * 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;
+	new->nfl_majorver = 4;
+	new->nfl_minorver = 0;
+	new->nfl_ttl = 300;
+}
+
+/**
+ * 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) {
+		free(new->nfl_hostname);
+		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;
+}
+
+/**
+ * Create a FedFS FSN record, return the new UUID
+ *
+ * @param host initialized NSDB host object
+ * @param nce NUL-terminated C string containing DN of NSDB container entry
+ * @param fsn_uuid OUT: freshly generated FSN UUID
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_create_fedfs_fsn() returns FEDFS_OK, caller must free
+ * the returned FSN UUID with free(3).
+ */
+static FedFsStatus
+nfsref_add_create_fedfs_fsn(nsdb_t host, const char *nce, char **fsn_uuid)
+{
+	unsigned int ldap_err;
+	FedFsStatus retval;
+	char *fsnuuid;
+	uuid_t uu;
+
+	fsnuuid = calloc(FEDFS_UUID_STRLEN, sizeof(char));
+	if (fsnuuid == NULL) {
+		xlog(D_GENERAL, "%s: No memory", __func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+	uuid_generate_time(uu);
+	uuid_unparse(uu, fsnuuid);
+
+	retval = nsdb_create_fsn_s(host, nce, fsnuuid,
+					nsdb_hostname(host), nsdb_port(host),
+					&ldap_err);
+	switch (retval) {
+	case FEDFS_OK:
+		xlog(D_GENERAL, "%s: Successfully created FSN record "
+			"for %s under %s", __func__, fsnuuid, nce);
+		*fsn_uuid = fsnuuid;
+		return FEDFS_OK;
+	case FEDFS_ERR_NSDB_NONCE:
+		xlog(L_ERROR, "NCE %s does not exist", nce);
+		break;
+	case FEDFS_ERR_NSDB_LDAP_VAL:
+		xlog(L_ERROR, "Failed to create FSN: %s",
+			ldap_err2string(ldap_err));
+		break;
+	default:
+		xlog(L_ERROR, "Failed to create FSN: %s",
+			nsdb_display_fedfsstatus(retval));
+	}
+
+	free(fsnuuid);
+	return retval;
+}
+
+/**
+ * Fill in default settings for NFSv4.0 fs_locations4
+ *
+ * @param rootpath NUL-terminated C string containing POSIX-style export path
+ * @param new fedfs_fsl object to fill in
+ *
+ * See section 5.1.3.2 of the NSDB protocol draft.
+ */
+static FedFsStatus
+nfsref_add_nfs_fsl_defaults(const char *rootpath, struct fedfs_nfs_fsl *new)
+{
+	FedFsStatus retval;
+
+	retval = nsdb_posix_to_path_array(rootpath, &new->fn_nfspath);
+	if (retval != FEDFS_OK)
+		return retval;
+
+	new->fn_majorver = 4;
+	new->fn_minorver = 0;
+	new->fn_currency = -1;
+	new->fn_gen_writable = false;
+	new->fn_gen_going = false;
+	new->fn_gen_split = true;
+	new->fn_trans_rdma = true;
+	new->fn_class_simul = 0;
+	new->fn_class_handle = 0;
+	new->fn_class_fileid = 0;
+	new->fn_class_writever = 0;
+	new->fn_class_change = 0;
+	new->fn_class_readdir = 0;
+	new->fn_readrank = 0;
+	new->fn_readorder = 0;
+	new->fn_writerank = 0;
+	new->fn_writeorder = 0;
+	new->fn_varsub = false;
+	new->fn_validfor = 0;
+
+	return FEDFS_OK;
+}
+
+/**
+ * Convert a pair of command line arguments to one fedfs_fsl structure
+ *
+ * @param fsn_uuid NUL-terminated C string containing FSN UUID to use
+ * @param host an initialized NSDB host object
+ * @param server NUL-terminated C string containing file server hostname
+ * @param rootpath NUL-terminated C string containing POSIX-style export path
+ * @param fsl OUT: fedfs_fsl object
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_build_fsl() returns FEDFS_OK, caller must free the
+ * returned fsl with nsdb_free_fedfs_fsl().
+ */
+static FedFsStatus
+nfsref_add_build_fsl(const char *fsn_uuid, nsdb_t host, const char *server,
+		const char *rootpath, struct fedfs_fsl **fsl)
+{
+	struct fedfs_fsl *new;
+	FedFsStatus retval;
+	uuid_t uu;
+
+	if (server == NULL || rootpath == NULL)
+		return FEDFS_ERR_INVAL;
+
+	new = nsdb_new_fedfs_fsl(FEDFS_NFS_FSL);
+	if (new == NULL) {
+		xlog(D_GENERAL, "%s: No memory", __func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+
+	uuid_generate_time(uu);
+	uuid_unparse(uu, new->fl_fsluuid);
+	strncpy(new->fl_fsnuuid, fsn_uuid, sizeof(new->fl_fsnuuid));
+	strncpy(new->fl_nsdbname, nsdb_hostname(host), sizeof(new->fl_nsdbname));
+	new->fl_nsdbport = nsdb_port(host);
+	strncpy(new->fl_fslhost, server, sizeof(new->fl_fslhost));
+	new->fl_fslport = 0;
+
+	retval = nfsref_add_nfs_fsl_defaults(rootpath, &new->fl_u.fl_nfsfsl);
+	if (retval != FEDFS_OK)
+		return retval;
+
+	*fsl = new;
+	return FEDFS_OK;
+}
+
+/**
+ * Convert command line options to a list of fedfs_fsl objects
+ *
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @param host an initialized NSDB host object
+ * @param fsn_uuid NUL-terminated C string containing FSN UUID to use
+ * @param fsls OUT a list of fedfs_fsl objects
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_build_fsl_list() returns FEDFS_OK, caller must free the
+ * returned list of fsls with nsdb_free_fedfs_fsls().
+ *
+ */
+static FedFsStatus
+nfsref_add_build_fsl_list(char **argv, int optind, nsdb_t host,
+		const char *fsn_uuid, struct fedfs_fsl **fsls)
+{
+	struct fedfs_fsl *fsl, *result = NULL;
+	FedFsStatus retval;
+	int i;
+
+	for (i = optind + 2; argv[i] != NULL; i += 2) {
+		retval = nfsref_add_build_fsl(fsn_uuid, host,
+						argv[i], argv[i + 1], &fsl);
+		if (retval != FEDFS_OK) {
+			nsdb_free_fedfs_fsls(result);
+			return retval;
+		}
+		if (result == NULL)
+			result = fsl;
+		else
+			result->fl_next = fsl;
+	}
+	if (result == NULL)
+		return FEDFS_ERR_INVAL;
+
+	*fsls = result;
+	return FEDFS_OK;
+}
+
+/**
+ * Set up FedFS FSLs, create a FedFS junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @param host an initialized and open NSDB object
+ * @param nce NUL-terminated C string containing DN of NSDB container entry
+ * @param fsn_uuid NUL-terminated C string containing FSN UUID to use
+ * @param fsls list of fedfs_fsl objects to create on NSDB
+ * @return a FedFsStatus code
+ */
+static FedFsStatus
+nfsref_add_create_fsls(const char *junct_path, nsdb_t host, const char *nce,
+		const char *fsn_uuid, struct fedfs_fsl *fsls)
+{
+	unsigned int ldap_err;
+	FedFsStatus retval;
+
+	retval = nsdb_create_fsls_s(host, nce, fsls, &ldap_err);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NSDB_NONCE:
+		xlog(L_ERROR, "NCE %s does not exist\n", nce);
+		return retval;
+	case FEDFS_ERR_NSDB_LDAP_VAL:
+		xlog(L_ERROR, "Failed to create FSL records: %s\n",
+			ldap_err2string(ldap_err));
+		return retval;
+	default:
+		xlog(D_GENERAL, "%s: Failed to create FSL records: %s\n",
+			__func__, nsdb_display_fedfsstatus(retval));
+		return retval;
+	}
+
+	retval = fedfs_add_junction(junct_path, fsn_uuid, host);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_EXIST:
+		xlog(L_ERROR, "%s already contains junction metadata",
+			junct_path);
+		break;
+	default:
+		xlog(L_ERROR, "Failed to FedFS junction: %s\n",
+			nsdb_display_fedfsstatus(retval));
+	}
+	return retval;
+}
+
+/**
+ * Set up FedFS FSLs, a FedFS FSN, and add it to a local 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
+ * @param host an initialized and open NSDB object
+ * @param nce NUL-terminated C string containing DN of NSDB container entry
+ * @param fsn_uuid NUL-terminated C string containing FSN UUID to use
+ * @return a FedFsStatus code
+ */
+static FedFsStatus
+nfsref_add_create_fedfs_junction(const char *junct_path, char **argv, int optind,
+		nsdb_t host, const char *nce, const char *fsn_uuid)
+{
+	struct fedfs_fsl *fsls;
+	FedFsStatus retval;
+
+	retval = nfsref_add_build_fsl_list(argv, optind, host, fsn_uuid, &fsls);
+	if (retval != FEDFS_OK)
+		return retval;
+
+	retval = nfsref_add_create_fsls(junct_path, host, nce, fsn_uuid, fsls);
+	nsdb_free_fedfs_fsls(fsls);
+	return retval;
+}
+
+/**
+ * Set up FedFS FSLs, a FedFS FSN, and add it to a local 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
+ * @param host an initialized and open NSDB object
+ * @param nce NUL-terminated C string containing DN of NSDB container entry
+ * @return program exit status
+ */
+static int
+nfsref_add_nfs_fedfs_junction(const char *junct_path, char **argv, int optind,
+		nsdb_t host, const char *nce)
+{
+	char *fsn_uuid = NULL;
+	FedFsStatus retval;
+
+	retval = nfsref_add_create_fedfs_fsn(host, nce, &fsn_uuid);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_INVAL:
+		xlog(L_ERROR, "Missing arguments or environment variables");
+		return EXIT_FAILURE;
+	case FEDFS_ERR_SVRFAULT:
+		xlog(L_ERROR, "No memory");
+		return EXIT_FAILURE;
+	default:
+		xlog(L_ERROR, "Failed to add FedFS junction to %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+
+	retval = nfsref_add_create_fedfs_junction(junct_path, argv, optind,
+							host, nce, fsn_uuid);
+	if (retval != FEDFS_OK) {
+		unsigned int ldap_err;
+		nsdb_delete_fsn_s(host, nce, fsn_uuid, false, &ldap_err);
+		free(fsn_uuid);
+		return EXIT_FAILURE;
+	}
+
+	printf("Created junction %s\n", junct_path);
+	free(fsn_uuid);
+	return EXIT_SUCCESS;
+}
+
+/**
+ * Set up FedFS FSLs, a FedFS FSN, and add it to a local 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_fedfs(const char *junct_path, char **argv, int optind)
+{
+	char *binddn, *bindpw, *nsdbname, *nce;
+	unsigned short nsdbport;
+	unsigned int ldap_err;
+	FedFsStatus retval;
+	nsdb_t host = NULL;
+	int status = EXIT_FAILURE;
+
+	xlog(D_GENERAL, "%s: Adding FedFS junction to %s",
+		__func__, junct_path);
+
+	nsdb_env(&nsdbname, &nsdbport, &binddn, &nce, &bindpw);
+	if (nsdbname == NULL) {
+		xlog(L_ERROR, "Cannot determine NSDB hostname");
+		return FEDFS_ERR_INVAL;
+	}
+
+	retval = nsdb_lookup_nsdb(nsdbname, nsdbport, &host, NULL);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NSDB_PARAMS:
+		xlog(L_ERROR, "No connection parameters for NSDB %s:%u\n",
+			nsdbname, nsdbport);
+		goto out;
+	default:
+		xlog(L_ERROR, "Failed to look up NSDB %s:%u: %s\n",
+			nsdbname, nsdbport, nsdb_display_fedfsstatus(retval));
+		goto out;
+	}
+	retval = FEDFS_ERR_INVAL;
+	if (binddn == NULL)
+		binddn = (char *)nsdb_default_binddn(host);
+	if (binddn == NULL) {
+		xlog(L_ERROR, "No NSDB bind DN was specified");
+		goto out_free;
+	}
+	if (nce == NULL)
+		nce = (char *)nsdb_default_nce(host);
+	if (nce == NULL) {
+		xlog(L_ERROR, "No NCE was specified");
+		goto out_free;
+	}
+
+	retval = nsdb_open_nsdb(host, binddn, bindpw, &ldap_err);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NSDB_CONN:
+		xlog(L_ERROR, "Failed to connect to NSDB %s:%u",
+			nsdbname, nsdbport);
+		goto out_free;
+	case FEDFS_ERR_NSDB_AUTH:
+		xlog(L_ERROR, "Failed to authenticate to NSDB %s:%u",
+			nsdbname, nsdbport);
+		goto out_free;
+	case FEDFS_ERR_NSDB_LDAP_VAL:
+		xlog(L_ERROR, "Failed to authenticate to NSDB %s:%u: %s",
+			nsdbname, nsdbport, ldap_err2string(ldap_err));
+		goto out_free;
+	default:
+		xlog(L_ERROR, "Failed to bind to NSDB %s:%u: %s",
+			nsdbname, nsdbport, nsdb_display_fedfsstatus(retval));
+		goto out_free;
+	}
+
+	status = nfsref_add_nfs_fedfs_junction(junct_path, argv, optind,
+								host, nce);
+
+	nsdb_close_nsdb(host);
+out_free:
+	nsdb_free_nsdb(host);
+out:
+	return status;
+}
+
+/**
+ * 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)
+{
+	switch (type) {
+	case NFSREF_TYPE_UNSPECIFIED:
+	case NFSREF_TYPE_NFS_BASIC:
+		return nfsref_add_nfs_basic(junct_path, argv, optind);
+	case NFSREF_TYPE_NFS_FEDFS:
+		return nfsref_add_nfs_fedfs(junct_path, argv, optind);
+	default:
+		xlog(L_ERROR, "Unrecognized junction type");
+	}
+	return EXIT_FAILURE;
+}
diff --git a/src/nfsref/lookup.c b/src/nfsref/lookup.c
new file mode 100644
index 0000000..861a4d0
--- /dev/null
+++ b/src/nfsref/lookup.c
@@ -0,0 +1,410 @@
+/**
+ * @file src/nfsref/lookup.c
+ * @brief Examine junction metadata from a local file system object
+ */
+
+/*
+ * 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
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "fedfs.h"
+#include "junction.h"
+#include "nsdb.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * 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 Version:\t%d.%d\n",
+		fsloc->nfl_majorver, fsloc->nfl_minorver);
+	printf("\tNFS port:\t%u\n", fsloc->nfl_hostport);
+	printf("\tValid for:\t%d\n", fsloc->nfl_validfor);
+	printf("\tCache TTL:\t%d\n", fsloc->nfl_ttl);
+	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;
+}
+
+/**
+ * Convert a boolean value into a displayable string constant (LDAP style)
+ *
+ * @param value boolean value
+ * @return NUL-terminated static constant C string
+ */
+static const char *
+nfsref_lookup_display_ldap_boolean(_Bool value)
+{
+	return value ? "TRUE" : "FALSE";
+}
+
+/**
+ * Display nfs_fsl portion of a fedfs_fsl structure
+ *
+ * @param nfsl pointer to a fedfs_nfs_fsl structure
+ */
+static void
+nfsref_lookup_display_fedfs_nfs_fsl(struct fedfs_nfs_fsl *nfsl)
+{
+	char *rootpath;
+
+	if (nsdb_path_array_to_posix(nfsl->fn_nfspath, &rootpath) == FEDFS_OK) {
+		printf("\tfedfsNfsPath:\t\t\t%s\n", rootpath);
+		free(rootpath);
+	} else
+		printf("\tfedfsNfsPath:\t\t\tInvalid\n");
+
+	printf("\tfedfsNfsMajorVer:\t\t%d\n", nfsl->fn_majorver);
+	printf("\tfedfsNfsMinorVer:\t\t%d\n", nfsl->fn_minorver);
+	printf("\tfedfsNfsCurrency:\t\t%d\n", nfsl->fn_currency);
+	printf("\tfedfsNfsGenFlagWritable:\t%s\n",
+		nfsref_lookup_display_ldap_boolean(nfsl->fn_gen_writable));
+	printf("\tfedfsNfsGenFlagGoing:\t\t%s\n",
+		nfsref_lookup_display_ldap_boolean(nfsl->fn_gen_going));
+	printf("\tfedfsNfsGenFlagSplit:\t\t%s\n",
+		nfsref_lookup_display_ldap_boolean(nfsl->fn_gen_split));
+	printf("\tfedfsNfsTransFlagRdma:\t\t%s\n",
+		nfsref_lookup_display_ldap_boolean(nfsl->fn_trans_rdma));
+	printf("\tfedfsNfsClassSimul:\t\t%u\n", nfsl->fn_class_simul);
+	printf("\tfedfsNfsClassHandle:\t\t%u\n", nfsl->fn_class_handle);
+	printf("\tfedfsNfsClassFileid:\t\t%u\n", nfsl->fn_class_fileid);
+	printf("\tfedfsNfsClassWritever:\t\t%u\n", nfsl->fn_class_writever);
+	printf("\tfedfsNfsClassChange:\t\t%u\n", nfsl->fn_class_change);
+	printf("\tfedfsNfsClassReaddir:\t\t%u\n", nfsl->fn_class_readdir);
+	printf("\tfedfsNfsReadRank:\t\t%d\n", nfsl->fn_readrank);
+	printf("\tfedfsNfsReadOrder:\t\t%d\n", nfsl->fn_readorder);
+	printf("\tfedfsNfsWriteRank:\t\t%d\n", nfsl->fn_writerank);
+	printf("\tfedfsNfsWriteOrder:\t\t%d\n", nfsl->fn_writeorder);
+	printf("\tfedfsNfsVarSub:\t\t\t%s\n",
+		nfsref_lookup_display_ldap_boolean(nfsl->fn_varsub));
+	printf("\tfedfsNfsValidFor:\t\t%d\n", nfsl->fn_validfor);
+}
+
+/**
+ * Display a single FedFS fileset location
+ *
+ * @param fsl pointer to a fedfs_fsl structure
+ */
+static void
+nfsref_lookup_display_fedfs_fsl(struct fedfs_fsl *fsl)
+{
+	int i;
+
+	printf("FedFS Fileset Location:\n");
+
+	printf("\tfedfsFslUuid:\t\t\t%s\n", fsl->fl_fsluuid);
+	printf("\tfedfsFsnUuid:\t\t\t%s\n", fsl->fl_fsnuuid);
+	printf("\tfedfsNsdbName:\t\t\t%s\n", fsl->fl_nsdbname);
+	printf("\tfedfsNsdbPort:\t\t\t%u\n", fsl->fl_nsdbport);
+	printf("\tfedfsFslHost:\t\t\t%s\n", fsl->fl_fslhost);
+	printf("\tfedfsFslPort:\t\t\t%u\n", fsl->fl_fslport);
+	printf("\tfedfsFslTTL:\t\t\t%d\n", fsl->fl_fslttl);
+
+	if (fsl->fl_annotations != NULL) {
+		for (i = 0; fsl->fl_annotations[i] != NULL; i++)
+			printf("\tfedfsAnnotation[%d]: %s\n", i,
+				fsl->fl_annotations[i]);
+	}
+
+	if (fsl->fl_description != NULL) {
+		for (i = 0; fsl->fl_description[i] != NULL; i++)
+			printf("\tfedfsDescr[%d]: %s\n", i,
+				fsl->fl_description[i]);
+	}
+
+	switch (fsl->fl_type) {
+	case FEDFS_NFS_FSL:
+		nfsref_lookup_display_fedfs_nfs_fsl(&fsl->fl_u.fl_nfsfsl);
+		break;
+	default:
+		printf("\tUnknown FedFS FSL type\n");
+	}
+
+	printf("\n");
+	fflush(stdout);
+}
+
+/**
+ * Display a list of FedFS fileset locations
+ *
+ * @param fsls list of FedFS fileset locations to display
+ */
+static void
+nfsref_lookup_display_fedfs_fsls(struct fedfs_fsl *fsls)
+{
+	struct fedfs_fsl *fsl;
+
+	for (fsl = fsls; fsl != NULL; fsl = fsl->fl_next)
+		nfsref_lookup_display_fedfs_fsl(fsl);
+}
+
+/**
+ * Resolve a FedFS fileset name
+ *
+ * @param fsn_uuid NUL-terminated C string containing FSN UUID to resolve
+ * @param host an initialized NSDB handle
+ * @return program exit status
+ */
+static int
+nfsref_lookup_resolve_fsn(const char *fsn_uuid, nsdb_t host)
+{
+	int status = EXIT_FAILURE;
+	struct fedfs_fsl *fsls;
+	unsigned int ldap_err;
+	FedFsStatus retval;
+
+	xlog(D_GENERAL, "%s: resolving FSN UUID %s with NSDB %s:%u",
+		__func__, fsn_uuid, nsdb_hostname(host), nsdb_port(host));
+
+	if (nsdb_open_nsdb(host, NULL, NULL, &ldap_err) != FEDFS_OK)
+		return status;
+
+	retval = nsdb_resolve_fsn_s(host, NULL, fsn_uuid, &fsls, &ldap_err);
+	switch (retval) {
+	case FEDFS_OK:
+		nfsref_lookup_display_fedfs_fsls(fsls);
+		nsdb_free_fedfs_fsls(fsls);
+		status = EXIT_SUCCESS;
+		break;
+	case FEDFS_ERR_NSDB_NOFSL:
+		xlog(L_ERROR, "%s: No FSL entries for FSN %s",
+			__func__, fsn_uuid);
+		break;
+	case FEDFS_ERR_NSDB_NOFSN:
+		xlog(L_ERROR, "%s: No FSN %s found",
+			__func__, fsn_uuid);
+		break;
+	case FEDFS_ERR_NSDB_LDAP_VAL:
+		xlog(L_ERROR, "%s: NSDB operation failed with %s",
+			__func__, ldap_err2string(ldap_err));
+		break;
+	default:
+		xlog(L_ERROR, "%s: Failed to resolve FSN %s: %s",
+			__func__, fsn_uuid, nsdb_display_fedfsstatus(status));
+	}
+
+	nsdb_close_nsdb(host);
+	return status;
+}
+
+/**
+ * Resolve a local FedFS-style junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_lookup_nfs_fedfs(const char *junct_path)
+{
+	FedFsStatus retval;
+	char *fsn_uuid;
+	nsdb_t host;
+	int status;
+
+	xlog(D_GENERAL, "%s: Looking up FedFS junction in %s",
+		__func__, junct_path);
+
+	retval = fedfs_is_junction(junct_path);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NOTJUNCT:
+		xlog(L_ERROR, "%s is not an nfs-fedfs 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 = fedfs_get_fsn(junct_path, &fsn_uuid, &host);
+	if (retval != FEDFS_OK) {
+		xlog(L_ERROR, "Failed to access %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+
+	status = nfsref_lookup_resolve_fsn(fsn_uuid, host);
+
+	free(fsn_uuid);
+	nsdb_free_nsdb(host);
+	return status;
+}
+
+/**
+ * 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);
+	if (retval != FEDFS_ERR_NOTJUNCT) {
+		xlog(L_ERROR, "Failed to access %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+	retval = fedfs_is_junction(junct_path);
+	if (retval == FEDFS_OK)
+		return nfsref_lookup_nfs_fedfs(junct_path);
+	if (retval != FEDFS_ERR_NOTJUNCT) {
+		xlog(L_ERROR, "Failed to access %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+	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);
+	case NFSREF_TYPE_NFS_FEDFS:
+		return nfsref_lookup_nfs_fedfs(junct_path);
+	default:
+		xlog(L_ERROR, "Unrecognized junction type");
+	}
+	return EXIT_FAILURE;
+}
diff --git a/src/nfsref/nfsref.c b/src/nfsref/nfsref.c
new file mode 100644
index 0000000..be05bda
--- /dev/null
+++ b/src/nfsref/nfsref.c
@@ -0,0 +1,187 @@
+/**
+ * @file src/nfsref/nfsref.c
+ * @brief Manage NFS referrals
+ */
+
+/*
+ * 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
+ */
+
+#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 "fedfs.h"
+#include "nsdb.h"
+#include "junction.h"
+#include "xlog.h"
+#include "gpl-boiler.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, "\n%s: version " VERSION "\n", 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);
+
+	fprintf(stderr, "%s", fedfs_gpl_boilerplate);
+}
+
+/**
+ * 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;
+
+	(void)umask(S_IWGRP | S_IWOTH);
+
+	exit_status = EXIT_FAILURE;
+
+	/* Ensure UTF-8 strings can be handled transparently */
+	if (setlocale(LC_CTYPE, "") == NULL ||
+	    strcmp(nl_langinfo(CODESET), "UTF-8") != 0) {
+		fprintf(stderr, "Failed to set locale and langinfo\n");
+		goto out;
+	}
+
+	/* 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;
+	}
+
+	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 {
+				fprintf(stderr,
+					"Unrecognized junction type: %s",
+					optarg);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case '?':
+			nfsref_usage(progname);
+			exit(EXIT_SUCCESS);
+		}
+	}
+	if (argc < optind + 2) {
+		fprintf(stderr, "Not enough positional parameters\n");
+		nfsref_usage(progname);
+		goto out;
+	}
+
+	if (geteuid() != 0) {
+		fprintf(stderr, "Root permission is required\n");
+		goto out;
+	}
+
+	subcommand = argv[optind];
+	junct_path = argv[optind + 1];
+
+	if (strcasecmp(subcommand, "add") == 0) {
+		if (argc < optind + 3) {
+			fprintf(stderr, "Not enough positional parameters\n");
+			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) {
+		exit_status = nfsref_remove(type, junct_path);
+		if (exit_status == EXIT_SUCCESS)
+			(void)junction_flush_exports_cache();
+	} else if (strcasecmp(subcommand, "lookup") == 0)
+		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/src/nfsref/nfsref.h b/src/nfsref/nfsref.h
new file mode 100644
index 0000000..8e40fd9
--- /dev/null
+++ b/src/nfsref/nfsref.h
@@ -0,0 +1,43 @@
+/**
+ * @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);
+
+#endif	/* !FEDFS_NFSREF_H */
diff --git a/src/nfsref/remove.c b/src/nfsref/remove.c
new file mode 100644
index 0000000..a0b46f8
--- /dev/null
+++ b/src/nfsref/remove.c
@@ -0,0 +1,163 @@
+/**
+ * @file src/nfsref/remove.c
+ * @brief Remove junction metadata from a local file system object
+ */
+
+/*
+ * 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
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "fedfs.h"
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * 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;
+		retval = fedfs_delete_junction(junct_path);
+		if (retval != FEDFS_OK)
+			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 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 a FedFS-style junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_remove_nfs_fedfs(const char *junct_path)
+{
+	int status = EXIT_FAILURE;
+	FedFsStatus retval;
+
+	xlog(D_GENERAL, "%s: Removing FedFS junction from %s",
+		__func__, junct_path);
+
+	retval = fedfs_delete_junction(junct_path);
+	switch (retval) {
+	case FEDFS_OK:
+		printf("Removed nfs-fedfs junction from %s\n", junct_path);
+		status = EXIT_SUCCESS;
+		break;
+	case FEDFS_ERR_NOTJUNCT:
+		xlog(L_ERROR, "%s is not an nfs-fedfs junction", junct_path);
+		break;
+	default:
+		xlog(L_ERROR, "Failed to delete %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+	}
+
+	return status;
+}
+
+/**
+ * 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);
+	case NFSREF_TYPE_NFS_FEDFS:
+		return nfsref_remove_nfs_fedfs(junct_path);
+	default:
+		xlog(L_ERROR, "Unrecognized junction type");
+	}
+	return EXIT_FAILURE;
+}
