changeset 3910:00586900e34c

6516085 sharemgr: should deliver 64-bit library objects for libshare.so and plugin(s) 6516121 sharemgr: libshare should provide better support for multithreaded apps
author dougm
date Wed, 28 Mar 2007 08:50:43 -0700
parents 9f4024db0edf
children 94df594513c7
files usr/src/Targetdirs usr/src/cmd/dfs.cmds/sharectl/sharectl.c usr/src/cmd/dfs.cmds/sharemgr/Makefile usr/src/cmd/dfs.cmds/sharemgr/Makefile.com usr/src/cmd/dfs.cmds/sharemgr/amd64/Makefile usr/src/cmd/dfs.cmds/sharemgr/commands.c usr/src/cmd/dfs.cmds/sharemgr/i386/Makefile usr/src/cmd/dfs.cmds/sharemgr/plugins/Makefile usr/src/cmd/dfs.cmds/sharemgr/plugins/Makefile.com usr/src/cmd/dfs.cmds/sharemgr/plugins/i386/Makefile usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.c usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.h usr/src/cmd/dfs.cmds/sharemgr/plugins/sparc/Makefile usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h usr/src/cmd/dfs.cmds/sharemgr/sharemgr_main.c usr/src/cmd/dfs.cmds/sharemgr/sparc/Makefile usr/src/cmd/dfs.cmds/sharemgr/sparcv9/Makefile usr/src/lib/libshare/Makefile usr/src/lib/libshare/Makefile.com usr/src/lib/libshare/amd64/Makefile usr/src/lib/libshare/common/libshare.c usr/src/lib/libshare/common/libshare.h usr/src/lib/libshare/common/libshare_impl.h usr/src/lib/libshare/common/libshare_zfs.c usr/src/lib/libshare/common/libsharecore.c usr/src/lib/libshare/common/mapfile-vers usr/src/lib/libshare/common/plugin.c usr/src/lib/libshare/common/scfutil.c usr/src/lib/libshare/common/scfutil.h usr/src/lib/libshare/nfs/Makefile usr/src/lib/libshare/nfs/Makefile.com usr/src/lib/libshare/nfs/amd64/Makefile usr/src/lib/libshare/nfs/i386/Makefile usr/src/lib/libshare/nfs/inc.flg usr/src/lib/libshare/nfs/libshare_nfs.c usr/src/lib/libshare/nfs/libshare_nfs.h usr/src/lib/libshare/nfs/mapfile-vers usr/src/lib/libshare/nfs/sparc/Makefile usr/src/lib/libshare/nfs/sparcv9/Makefile usr/src/lib/libshare/sparcv9/Makefile usr/src/pkgdefs/SUNWarc/prototype_i386 usr/src/pkgdefs/SUNWarc/prototype_sparc usr/src/pkgdefs/SUNWcsu/prototype_com usr/src/pkgdefs/SUNWcsu/prototype_i386 usr/src/pkgdefs/SUNWcsu/prototype_sparc usr/src/pkgdefs/SUNWnfssu/prototype_com usr/src/pkgdefs/SUNWnfssu/prototype_i386 usr/src/pkgdefs/SUNWnfssu/prototype_sparc usr/src/pkgdefs/etc/exception_list_i386 usr/src/pkgdefs/etc/exception_list_sparc
diffstat 50 files changed, 4084 insertions(+), 3545 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/Targetdirs	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/Targetdirs	Wed Mar 28 08:50:43 2007 -0700
@@ -379,7 +379,8 @@
 ROOT.SYS64.2 = \
 	$($(MACH64)_ROOT.SYS64.2) \
 	/usr/lib/mdb/kvm/$(MACH64) \
-	/usr/lib/mdb/proc/$(MACH64)
+	/usr/lib/mdb/proc/$(MACH64) \
+	/usr/lib/fs/nfs/$(MACH64)
 
 UUCP.UUCP= \
 	/var/spool/uucp \
--- a/usr/src/cmd/dfs.cmds/sharectl/sharectl.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharectl/sharectl.c	Wed Mar 28 08:50:43 2007 -0700
@@ -40,7 +40,7 @@
 #include <libintl.h>
 #include <locale.h>
 
-static int run_command(char *, int, char **);
+static int run_command(char *, int, char **, sa_handle_t);
 static void sub_command_help(char *proto);
 
 static void
@@ -57,6 +57,7 @@
 	int help = 0;
 	int rval;
 	char *command;
+	sa_handle_t handle;
 
 	/*
 	 * make sure locale and gettext domain is setup
@@ -64,7 +65,7 @@
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
-	sa_init(SA_INIT_CONTROL_API);
+	handle = sa_init(SA_INIT_CONTROL_API);
 
 	while ((c = getopt(argc, argv, "h?")) != EOF) {
 	    switch (c) {
@@ -87,9 +88,9 @@
 	 * now have enough to parse rest of command line
 	 */
 	command = argv[optind];
-	rval = run_command(command, argc - optind, argv + optind);
+	rval = run_command(command, argc - optind, argv + optind, handle);
 
-	sa_fini();
+	sa_fini(handle);
 	return (rval);
 }
 
@@ -112,16 +113,14 @@
 	return (ret);
 }
 
+/*ARGSUSED*/
 static int
-sc_get(int flags, int argc, char *argv[])
+sc_get(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *proto = NULL;
 	struct options *optlist = NULL;
 	int ret = SA_OK;
 	int c;
-#ifdef lint
-	flags = flags;
-#endif
 
 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
 	    switch (c) {
@@ -203,16 +202,14 @@
 	return (ret);
 }
 
+/*ARGSUSED*/
 static int
-sc_set(int flags, int argc, char *argv[])
+sc_set(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *proto = NULL;
 	struct options *optlist = NULL;
 	int ret = SA_OK;
 	int c;
-#ifdef lint
-	flags = flags;
-#endif
 
 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
 	    switch (c) {
@@ -316,8 +313,9 @@
 	return (0);
 }
 
+/*ARGSUSED*/
 static int
-sc_status(int flags, int argc, char *argv[])
+sc_status(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char **protos;
 	int ret = SA_OK;
@@ -325,9 +323,6 @@
 	int i;
 	int num_proto;
 	int verbose = 0;
-#ifdef lint
-	flags = flags;
-#endif
 
 	while ((c = getopt(argc, argv, "?hv")) != EOF) {
 	    switch (c) {
@@ -374,13 +369,11 @@
 	{NULL, 0, NULL, 0},
 };
 
+/*ARGSUSED*/
 void
 sub_command_help(char *proto)
 {
 	int i;
-#ifdef lint
-	proto = proto;
-#endif
 
 	(void) printf("\tsub-commands:\n");
 	for (i = 0; commands[i].cmdname != NULL; i++) {
@@ -405,7 +398,7 @@
 }
 
 static int
-run_command(char *command, int argc, char *argv[])
+run_command(char *command, int argc, char *argv[], sa_handle_t handle)
 {
 	sa_command_t *cmdvec;
 	int ret;
@@ -435,6 +428,6 @@
 	 * need to check priviledges and restrict what can be done
 	 * based on least priviledge and sub-command.
 	 */
-	ret = cmdvec->cmdfunc(NULL, argc, argv);
+	ret = cmdvec->cmdfunc(handle, NULL, argc, argv);
 	return (ret);
 }
--- a/usr/src/cmd/dfs.cmds/sharemgr/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -21,10 +21,9 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-DEFAULTFILES = 
 
 MANIFEST  = group.xml
 
@@ -33,7 +32,8 @@
 #
 # One for each ISA.
 #
-SUBDIRS =	$(MACH) plugins
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
 
 ROOTMANIFESTDIR	= $(ROOTSVCNETWORKSHARES)
 $(ROOTMANIFEST)		:= FILEMODE= 444
@@ -49,9 +49,9 @@
 
 all clean clobber lint _msg:	$(SUBDIRS)
 
-install: $(SUBDIRS) $(ROOTETCDEFAULTFILES) $(ROOTMANIFEST)
+install: $(SUBDIRS) $(ROOTMANIFEST)
 
-$(SUBDIRS):	FRC
+$(SUBDIRS) $(TESTSUBS):	FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
 
 FRC:
--- a/usr/src/cmd/dfs.cmds/sharemgr/Makefile.com	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/Makefile.com	Wed Mar 28 08:50:43 2007 -0700
@@ -21,7 +21,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -31,10 +31,6 @@
 
 PROG=		sharemgr
 
-LINK_SRCS = libshare_nfs.c
-LINK_OBJS = libshare_nfs.o
-LINK_MODS = libshare_nfs.so
-
 SHAREMGR_MOD	= sharemgr
 
 COMMONSRC	= sharemgr_main.c commands.c shareutil.c
@@ -51,6 +47,7 @@
 LDLIBS += -lshare -lscf -lsecdb -lumem
 all install := LDLIBS += -lxml2
 LINTFLAGS	+= -u
+LINTFLAGS64	+= -u
 
 SRCS = $(SHAREMGR_SRC)
 OBJS = $(SHAREMGR_OBJ)
@@ -78,7 +75,7 @@
 	$(LINK.c) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
 	$(POST_PROCESS)
 
-install: all $(ROOTUSRSBINPROG) $(ROOTLINKS)
+install: all
 
 $(ROOTLINKS): $(ROOTUSRSBINPROG)
 	$(RM) $@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/dfs.cmds/sharemgr/amd64/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.cmd.64
+
+install: all $(ROOTUSRSBINPROG64)
--- a/usr/src/cmd/dfs.cmds/sharemgr/commands.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/commands.c	Wed Mar 28 08:50:43 2007 -0700
@@ -255,8 +255,8 @@
  *	was passed in.
  */
 static int
-enable_all_groups(struct list *work, int setstate, int online,
-	char *updateproto)
+enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
+	int online, char *updateproto)
 {
 	int ret = SA_OK;
 	char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
@@ -319,7 +319,7 @@
 	    }
 	}
 	if (ret == SA_OK) {
-	    ret = sa_update_config();
+	    ret = sa_update_config(handle);
 	}
 	return (ret);
 }
@@ -517,7 +517,7 @@
  *	No protocol means "all" protocols in this case.
  */
 static int
-sa_create(int flags, int argc, char *argv[])
+sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *groupname;
 
@@ -612,7 +612,7 @@
 
 	auth = check_authorizations(groupname, flags);
 
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group != NULL) {
 	    /* group exists so must be a protocol add */
 	    if (protocol != NULL) {
@@ -647,7 +647,7 @@
 	}
 	if (ret == SA_OK && !dryrun) {
 	    if (group == NULL) {
-		group = sa_create_group((char *)groupname, &err);
+		group = sa_create_group(handle, (char *)groupname, &err);
 	    }
 	    if (group != NULL) {
 		sa_optionset_t optionset;
@@ -678,7 +678,7 @@
 			 * all protocols that implement the
 			 * appropriate plugin.
 			 */
-		    ret = sa_update_config();
+		    ret = sa_update_config(handle);
 		} else {
 		    if (group != NULL)
 			(void) sa_remove_group(group);
@@ -727,7 +727,7 @@
  */
 
 static int
-sa_delete(int flags, int argc, char *argv[])
+sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *groupname;
 	sa_group_t group;
@@ -803,7 +803,7 @@
 	 */
 
 	groupname = argv[optind];
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group == NULL) {
 		ret = SA_NO_SUCH_GROUP;
 	} else {
@@ -832,7 +832,7 @@
 		}
 		/* commit to configuration if not a dryrun */
 		if (!dryrun && ret == SA_OK) {
-		    ret = sa_update_config();
+		    ret = sa_update_config(handle);
 		}
 	    } else {
 		/* a protocol delete */
@@ -969,7 +969,7 @@
  */
 
 static int
-sa_list(int flags, int argc, char *argv[])
+sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	sa_group_t group;
 	int verbose = 0;
@@ -1001,7 +1001,7 @@
 	    }
 	}
 
-	for (group = sa_get_group(NULL); group != NULL;
+	for (group = sa_get_group(handle, NULL); group != NULL;
 	    group = sa_get_next_group(group)) {
 	    char *name;
 	    char *proto;
@@ -1302,7 +1302,7 @@
  */
 
 int
-sa_show(int flags, int argc, char *argv[])
+sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	sa_group_t group;
 	int verbose = 0;
@@ -1351,7 +1351,7 @@
 
 	if (optind == argc) {
 	    /* no group specified so go through them all */
-	    for (group = sa_get_group(NULL); group != NULL;
+	    for (group = sa_get_group(handle, NULL); group != NULL;
 		group = sa_get_next_group(group)) {
 		/*
 		 * have a group so check if one we want and then list
@@ -1365,7 +1365,7 @@
 	} else {
 	    /* have a specified list of groups */
 	    for (; optind < argc; optind++) {
-		group = sa_get_group(argv[optind]);
+		group = sa_get_group(handle, argv[optind]);
 		if (group != NULL) {
 		    if (xml)
 			show_group_xml(doc, group);
@@ -1392,7 +1392,8 @@
  */
 
 static int
-enable_share(sa_group_t group, sa_share_t share, int update_legacy)
+enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
+		int update_legacy)
 {
 	char *value;
 	int enabled;
@@ -1438,7 +1439,7 @@
 	    }
 	}
 	if (ret == SA_OK)
-	    (void) sa_update_config();
+	    (void) sa_update_config(handle);
 	return (ret);
 }
 
@@ -1449,7 +1450,7 @@
  */
 
 int
-sa_addshare(int flags, int argc, char *argv[])
+sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int dryrun = 0;
@@ -1539,10 +1540,10 @@
 		}
 	    }
 	    if (ret == SA_OK) {
-		group = sa_get_group(argv[optind]);
+		group = sa_get_group(handle, argv[optind]);
 		if (group != NULL) {
 		    auth = check_authorizations(argv[optind], flags);
-		    share = sa_find_share(sharepath);
+		    share = sa_find_share(handle, sharepath);
 		    if (share != NULL) {
 			group = sa_get_parent_group(share);
 			if (group != NULL) {
@@ -1596,8 +1597,8 @@
 				}
 				if (ret == SA_OK) {
 				    /* now enable the share(s) */
-				    ret = enable_share(group, share, 1);
-				    ret = sa_update_config();
+				    ret = enable_share(handle, group, share, 1);
+				    ret = sa_update_config(handle);
 				}
 				switch (ret) {
 				case SA_DUPLICATE_NAME:
@@ -1639,7 +1640,7 @@
  */
 
 int
-sa_moveshare(int flags, int argc, char *argv[])
+sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int dryrun = 0;
@@ -1698,9 +1699,9 @@
 				"the -s option\n"));
 		ret = SA_BAD_PATH;
 	    } else {
-		group = sa_get_group(argv[optind]);
+		group = sa_get_group(handle, argv[optind]);
 		if (group != NULL) {
-		    share = sa_find_share(sharepath);
+		    share = sa_find_share(handle, sharepath);
 		    authdst = check_authorizations(argv[optind], flags);
 		    if (share == NULL) {
 			(void) printf(gettext("Share not found: %s\n"),
@@ -1735,7 +1736,7 @@
 			}
 			if (ret == SA_OK && parent != group && !dryrun) {
 			    char *oldstate;
-			    ret = sa_update_config();
+			    ret = sa_update_config(handle);
 				/*
 				 * note that the share may need to be
 				 * "unshared" if the new group is
@@ -1748,7 +1749,7 @@
 			    if (strcmp(oldstate, "enabled") == 0) {
 				(void) sa_disable_share(share, NULL);
 			    }
-			    (void) enable_share(group, share, 1);
+			    (void) enable_share(handle, group, share, 1);
 			    if (oldstate != NULL)
 				sa_free_attr_string(oldstate);
 			}
@@ -1779,7 +1780,7 @@
  */
 
 int
-sa_removeshare(int flags, int argc, char *argv[])
+sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int dryrun = 0;
@@ -1841,7 +1842,7 @@
 						"command\n"));
 		    ret = SA_SYNTAX_ERR;
 		} else {
-		    group = sa_get_group(argv[optind]);
+		    group = sa_get_group(handle, argv[optind]);
 		    if (group == NULL) {
 			(void) printf(gettext("Group \"%s\" not found\n"),
 					argv[optind]);
@@ -1862,7 +1863,7 @@
 		if (group != NULL)
 		    share = sa_get_share(group, sharepath);
 		else
-		    share = sa_find_share(sharepath);
+		    share = sa_find_share(handle, sharepath);
 		/*
 		 * If we didn't find the share with the provided path,
 		 * it may be a symlink so attempt to resolve it using
@@ -1882,7 +1883,7 @@
 			if (group != NULL)
 			    share = sa_get_share(group, dir);
 			else
-			    share = sa_find_share(dir);
+			    share = sa_find_share(handle, dir);
 		    }
 		}
 	    }
@@ -1923,7 +1924,7 @@
 				ret = sa_remove_share(share);
 			    }
 			    if (ret == SA_OK)
-				ret = sa_update_config();
+				ret = sa_update_config(handle);
 			}
 			if (ret != SA_OK) {
 			    (void) printf(gettext("Could not remove share:"
@@ -1955,7 +1956,7 @@
  */
 
 int
-sa_set_share(int flags, int argc, char *argv[])
+sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int dryrun = 0;
 	int c;
@@ -2022,12 +2023,12 @@
 	    char *groupname;
 	    if (optind < argc) {
 		groupname = argv[optind];
-		group = sa_get_group(groupname);
+		group = sa_get_group(handle, groupname);
 	    } else {
 		group = NULL;
 		groupname = NULL;
 	    }
-	    share = sa_find_share(sharepath);
+	    share = sa_find_share(handle, sharepath);
 	    if (share != NULL) {
 		sharegroup = sa_get_parent_group(share);
 		if (group != NULL && group != sharegroup) {
@@ -2073,7 +2074,7 @@
 		    }
 		}
 		if (!dryrun && ret == SA_OK) {
-		    ret = sa_update_config();
+		    ret = sa_update_config(handle);
 		}
 		switch (ret) {
 		case SA_DUPLICATE_NAME:
@@ -2184,15 +2185,15 @@
  */
 
 static int
-basic_set(char *groupname, struct options *optlist, char *protocol,
-		char *sharepath, int dryrun)
+basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
+		char *protocol,	char *sharepath, int dryrun)
 {
 	sa_group_t group;
 	int ret = SA_OK;
 	int change = 0;
 	struct list *worklist = NULL;
 
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group != NULL) {
 	    sa_share_t share = NULL;
 	    if (sharepath != NULL) {
@@ -2232,7 +2233,7 @@
 	if (!dryrun && ret == SA_OK) {
 	    if (change && worklist != NULL) {
 		/* properties changed, so update all shares */
-		(void) enable_all_groups(worklist, 0, 0, protocol);
+		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
 	    }
 	}
 	if (worklist != NULL)
@@ -2249,8 +2250,8 @@
  */
 
 static int
-space_set(char *groupname, struct options *optlist, char *protocol,
-		char *sharepath, int dryrun, char *sectype)
+space_set(sa_handle_t handle, char *groupname, struct options *optlist,
+		char *protocol,	char *sharepath, int dryrun, char *sectype)
 {
 	sa_group_t group;
 	int ret = SA_OK;
@@ -2268,7 +2269,7 @@
 	    return (SA_INVALID_SECURITY);
 	}
 
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group != NULL) {
 	    sa_share_t share = NULL;
 	    if (sharepath != NULL) {
@@ -2312,9 +2313,9 @@
 	if (!dryrun && ret == 0) {
 	    if (change && worklist != NULL) {
 		/* properties changed, so update all shares */
-		(void) enable_all_groups(worklist, 0, 0, protocol);
+		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
 	    }
-	    ret = sa_update_config();
+	    ret = sa_update_config(handle);
 	}
 	if (worklist != NULL)
 	    free_list(worklist);
@@ -2329,7 +2330,7 @@
  */
 
 int
-sa_set(int flags, int argc, char *argv[])
+sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *groupname;
 	int verbose = 0;
@@ -2422,10 +2423,10 @@
 	    groupname = argv[optind];
 	    auth = check_authorizations(groupname, flags);
 	    if (optset == NULL)
-		ret = basic_set(groupname, optlist, protocol,
+		ret = basic_set(handle, groupname, optlist, protocol,
 				sharepath, dryrun);
 	    else
-		ret = space_set(groupname, optlist, protocol,
+		ret = space_set(handle, groupname, optlist, protocol,
 				sharepath, dryrun, optset);
 	    if (dryrun && ret == SA_OK && !auth && verbose) {
 		(void) printf(gettext("Command would fail: %s\n"),
@@ -2594,15 +2595,15 @@
  */
 
 static int
-basic_unset(char *groupname, struct options *optlist, char *protocol,
-		char *sharepath, int dryrun)
+basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
+		char *protocol,	char *sharepath, int dryrun)
 {
 	sa_group_t group;
 	int ret = SA_OK;
 	int change = 0;
 	struct list *worklist = NULL;
 
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group != NULL) {
 	    sa_share_t share = NULL;
 	    if (sharepath != NULL) {
@@ -2656,7 +2657,7 @@
 	if (!dryrun && ret == SA_OK) {
 	    if (change && worklist != NULL) {
 		/* properties changed, so update all shares */
-		(void) enable_all_groups(worklist, 0, 0, protocol);
+		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
 	    }
 	}
 	if (worklist != NULL)
@@ -2670,15 +2671,15 @@
  * unset named optionset properties.
  */
 static int
-space_unset(char *groupname, struct options *optlist, char *protocol,
-		char *sharepath, int dryrun, char *sectype)
+space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
+		char *protocol, char *sharepath, int dryrun, char *sectype)
 {
 	sa_group_t group;
 	int ret = SA_OK;
 	int change = 0;
 	struct list *worklist = NULL;
 
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group != NULL) {
 	    sa_share_t share = NULL;
 	    if (sharepath != NULL) {
@@ -2750,9 +2751,9 @@
 	if (!dryrun && ret == 0) {
 	    if (change && worklist != NULL) {
 		/* properties changed, so update all shares */
-		(void) enable_all_groups(worklist, 0, 0, protocol);
+		(void) enable_all_groups(handle, worklist, 0, 0, protocol);
 	    }
-	    ret = sa_update_config();
+	    ret = sa_update_config(handle);
 	}
 	if (worklist != NULL)
 	    free_list(worklist);
@@ -2767,7 +2768,7 @@
  */
 
 int
-sa_unset(int flags, int argc, char *argv[])
+sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *groupname;
 	int verbose = 0;
@@ -2862,10 +2863,10 @@
 	    groupname = argv[optind];
 	    auth = check_authorizations(groupname, flags);
 	    if (optset == NULL)
-		ret = basic_unset(groupname, optlist, protocol,
+		ret = basic_unset(handle, groupname, optlist, protocol,
 					sharepath, dryrun);
 	    else
-		ret = space_unset(groupname, optlist, protocol,
+		ret = space_unset(handle, groupname, optlist, protocol,
 					sharepath, dryrun, optset);
 
 	    if (dryrun && ret == SA_OK && !auth && verbose) {
@@ -2883,7 +2884,7 @@
  */
 
 int
-sa_enable_group(int flags, int argc, char *argv[])
+sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int dryrun = 0;
@@ -2931,7 +2932,7 @@
 	    sa_group_t group;
 	    if (!all) {
 		while (optind < argc) {
-		    group = sa_get_group(argv[optind]);
+		    group = sa_get_group(handle, argv[optind]);
 		    if (group != NULL) {
 			auth &= check_authorizations(argv[optind], flags);
 			state = sa_get_group_attr(group, "state");
@@ -2958,13 +2959,13 @@
 		    optind++;
 		}
 	    } else {
-		for (group = sa_get_group(NULL); group != NULL;
+		for (group = sa_get_group(handle, NULL); group != NULL;
 		    group = sa_get_next_group(group)) {
 		    worklist = add_list(worklist, group, 0);
 		}
 	    }
 	    if (!dryrun && ret == SA_OK) {
-		ret = enable_all_groups(worklist, 1, 0, NULL);
+		ret = enable_all_groups(handle, worklist, 1, 0, NULL);
 	    }
 	    if (ret != SA_OK && ret != SA_BUSY)
 		(void) printf(gettext("Could not enable group: %s\n"),
@@ -3021,7 +3022,7 @@
  */
 
 static int
-disable_all_groups(struct list *work, int setstate)
+disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
 {
 	int ret = SA_OK;
 	sa_group_t subgroup, group;
@@ -3052,7 +3053,7 @@
 	    work = work->next;
 	}
 	if (ret == SA_OK)
-	    ret = sa_update_config();
+	    ret = sa_update_config(handle);
 	return (ret);
 }
 
@@ -3063,7 +3064,7 @@
  */
 
 int
-sa_disable_group(int flags, int argc, char *argv[])
+sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int dryrun = 0;
@@ -3112,7 +3113,7 @@
 		sa_group_t group;
 		if (!all) {
 		    while (optind < argc) {
-			group = sa_get_group(argv[optind]);
+			group = sa_get_group(handle, argv[optind]);
 			if (group != NULL) {
 			    auth &= check_authorizations(argv[optind], flags);
 			    state = sa_get_group_attr(group, "state");
@@ -3139,13 +3140,13 @@
 			optind++;
 		    }
 		} else {
-		    for (group = sa_get_group(NULL); group != NULL;
+		    for (group = sa_get_group(handle, NULL); group != NULL;
 			    group = sa_get_next_group(group)) {
 			worklist = add_list(worklist, group, 0);
 		    }
 		}
 		if (ret == SA_OK && !dryrun) {
-			ret = disable_all_groups(worklist, 1);
+			ret = disable_all_groups(handle, worklist, 1);
 		}
 		if (ret != SA_OK && ret != SA_BUSY)
 		    (void) printf(gettext("Could not disable group: %s\n"),
@@ -3206,7 +3207,7 @@
  */
 
 int
-sa_start_group(int flags, int argc, char *argv[])
+sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int all = 0;
@@ -3255,7 +3256,7 @@
 
 		if (!all) {
 		    while (optind < argc) {
-			group = sa_get_group(argv[optind]);
+			group = sa_get_group(handle, argv[optind]);
 			if (group != NULL) {
 			    state = sa_get_group_attr(group, "state");
 			    if (state == NULL ||
@@ -3282,7 +3283,7 @@
 			optind++;
 		    }
 		} else {
-		    for (group = sa_get_group(NULL); group != NULL;
+		    for (group = sa_get_group(handle, NULL); group != NULL;
 			    group = sa_get_next_group(group)) {
 			state = sa_get_group_attr(group, "state");
 			if (state == NULL || strcmp(state, "enabled") == 0)
@@ -3291,7 +3292,7 @@
 			    sa_free_attr_string(state);
 		    }
 		}
-		(void) enable_all_groups(worklist, 0, 1, NULL);
+		(void) enable_all_groups(handle, worklist, 0, 1, NULL);
 	}
 	if (worklist != NULL)
 	    free_list(worklist);
@@ -3308,7 +3309,7 @@
  */
 
 int
-sa_stop_group(int flags, int argc, char *argv[])
+sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	int verbose = 0;
 	int all = 0;
@@ -3353,7 +3354,7 @@
 		sa_group_t group;
 		if (!all) {
 		    while (optind < argc) {
-			group = sa_get_group(argv[optind]);
+			group = sa_get_group(handle, argv[optind]);
 			if (group != NULL) {
 			    state = sa_get_group_attr(group, "state");
 			    if (state == NULL ||
@@ -3372,7 +3373,7 @@
 			optind++;
 		    }
 		} else {
-		    for (group = sa_get_group(NULL); group != NULL;
+		    for (group = sa_get_group(handle, NULL); group != NULL;
 			    group = sa_get_next_group(group)) {
 			state = sa_get_group_attr(group, "state");
 			if (state == NULL || strcmp(state, "enabled") == 0)
@@ -3381,8 +3382,8 @@
 			    sa_free_attr_string(state);
 		    }
 		}
-		(void) disable_all_groups(worklist, 0);
-		ret = sa_update_config();
+		(void) disable_all_groups(handle, worklist, 0);
+		ret = sa_update_config(handle);
 	}
 	if (worklist != NULL)
 	    free_list(worklist);
@@ -3588,11 +3589,11 @@
  */
 
 static void
-output_legacy_file(FILE *out, char *proto)
+output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
 {
 	sa_group_t group;
 
-	for (group = sa_get_group(NULL); group != NULL;
+	for (group = sa_get_group(handle, NULL); group != NULL;
 		group = sa_get_next_group(group)) {
 	    char *options;
 	    char *zfs;
@@ -3624,7 +3625,7 @@
 }
 
 int
-sa_legacy_share(int flags, int argc, char *argv[])
+sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *protocol = "nfs";
 	char *options = NULL;
@@ -3686,7 +3687,7 @@
 	/* have the info so construct what is needed */
 	if (!argsused && optind == argc) {
 	    /* display current info in share format */
-	    (void) output_legacy_file(stdout, "nfs");
+	    (void) output_legacy_file(stdout, "nfs", handle);
 	} else {
 	    sa_group_t group = NULL;
 	    sa_share_t share;
@@ -3717,7 +3718,7 @@
 	    else
 		sharepath = dir;
 	    if (ret == SA_OK) {
-		share = sa_find_share(sharepath);
+		share = sa_find_share(handle, sharepath);
 	    } else {
 		share = NULL;
 	    }
@@ -3738,7 +3739,7 @@
 		 */
 		    group = sa_get_parent_group(share);
 		} else {
-		    group = sa_get_group(legacygroup);
+		    group = sa_get_group(handle, legacygroup);
 		}
 		if (group != NULL) {
 		    groupstatus = group_status(group);
@@ -3746,9 +3747,9 @@
 			share = sa_add_share(group, sharepath, persist, &ret);
 			if (share == NULL && ret == SA_DUPLICATE_NAME) {
 			    /* could be a ZFS path being started */
-			    if (sa_zfs_is_shared(sharepath)) {
+			    if (sa_zfs_is_shared(handle, sharepath)) {
 				ret = SA_OK;
-				group = sa_get_group("zfs");
+				group = sa_get_group(handle, "zfs");
 				if (group == NULL) {
 				    /* this shouldn't happen */
 				    ret = SA_CONFIG_ERR;
@@ -3767,7 +3768,7 @@
 			 * need to change them regardless of the
 			 * source.
 			 */
-			if (sa_zfs_is_shared(sharepath)) {
+			if (sa_zfs_is_shared(handle, sharepath)) {
 			    zfs = 1;
 			}
 			remove_all_options(share, protocol);
@@ -3810,7 +3811,7 @@
 			    (void) sa_update_legacy(share, protocol);
 			}
 			if (ret == SA_OK)
-			    ret = sa_update_config();
+			    ret = sa_update_config(handle);
 		    }
 		} else {
 		    ret = SA_SYSTEM_ERR;
@@ -3833,7 +3834,7 @@
  */
 
 int
-sa_legacy_unshare(int flags, int argc, char *argv[])
+sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
 {
 	char *protocol = "nfs"; /* for now */
 	char *options = NULL;
@@ -3899,12 +3900,12 @@
 		 * realpath() and try again.
 		 */
 	    sharepath = argv[optind++];
-	    share = sa_find_share(sharepath);
+	    share = sa_find_share(handle, sharepath);
 	    if (share == NULL) {
 		if (realpath(sharepath, dir) == NULL) {
 		    ret = SA_NO_SUCH_PATH;
 		} else {
-		    share = sa_find_share(dir);
+		    share = sa_find_share(handle, dir);
 		}
 	    }
 	    if (share != NULL) {
@@ -3920,7 +3921,7 @@
 		if (persist == SA_SHARE_PERMANENT) {
 		    ret = sa_remove_share(share);
 		    if (ret == SA_OK)
-			ret = sa_update_config();
+			ret = sa_update_config(handle);
 		}
 	    } else {
 		ret = SA_NOT_SHARED;
--- a/usr/src/cmd/dfs.cmds/sharemgr/i386/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/i386/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -21,10 +21,10 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 include ../Makefile.com
 
-install: all
+install: all $(ROOTUSRSBINPROG32) $(ROOTLINKS)
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-DEFAULTFILES = 
-
-include ../../../Makefile.cmd
-
-#
-# One for each ISA.
-#
-SUBDIRS =	$(MACH)
-
-all	:=	TARGET= all
-install	:=	TARGET= install
-clean	:=	TARGET= clean
-clobber	:=	TARGET= clobber
-_msg	:=	TARGET= _msg
-lint	:=	TARGET= lint
-
-.KEEP_STATE:
-
-all clean clobber lint _msg:	$(SUBDIRS)
-
-install: $(SUBDIRS) $(ROOTETCDEFAULTFILES)
-
-$(SUBDIRS):	FRC
-	@cd $@; pwd; $(MAKE) $(TARGET)
-
-FRC:
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/Makefile.com	Wed Mar 28 07:55:32 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../../../../Makefile.cmd
-
-COMMON = ..
-
-NFS_MOD		= libshare_nfs.so
-NFS_SRC		= $(NFS_MOD:%.so=$(COMMON)/%.c)
-NFSLIB_DIR	= $(SRC)/cmd/fs.d/nfs/lib
-
-SHAREDSRC1	= nfs_sec.c
-SHAREDSRC2	= nfslog_config.c
-SHAREDSRC3	= nfslogtab.c
-NFS_SRCS	= $(COMMON)/$(SHAREDSRC1) \
-		$(COMMON)/$(SHAREDSRC2) $(COMMON)/$(SHAREDSRC3) $(NFS_SRC)
-NFS_OBJS	= libshare_nfs.o nfs_sec.o nfslog_config.o nfslogtab.o
-
-LINK_SRCS	= $(NFS_SRC)
-
-LINT_MODULES 	= $(LINK_SRCS:.c=.ln)
-# -u to eliminate XML warnings.
-LINTFLAGS	+= -u
-
-LINK_OBJS	= $(NFS_OBJS)
-
-LINK_MODS	= $(NFS_MOD)
-
-SRCS	= $(LINK_SRCS)
-OBJS	= $(LINK_OBJS)
-MODS	= $(LINK_MODS)
-
-NFS_DIR		= fs/nfs
-ROOTLIB_NFS_LINKMOD = $(ROOTLIB)/$(NFS_DIR)
-ROOTLIB_NFS_LINK_MODS	= $(LINK_MODS:%=$(ROOTLIB_NFS_LINKMOD)/%)
-
-CLOBBERFILES = $(MODS) $(SHAREDSRC)
-
-MYCPPFLAGS = -I$(SRC)/lib/libshare/common -I$(SRC)/lib/libfsmgt/common \
-		-I/usr/include/libxml2 -I.. -I../.. \
-		-I../../../../fs.d/nfs/lib
-CPPFLAGS += $(MYCPPFLAGS)
-LDLIBS += -lshare -lnsl -lscf -lumem -lc
-all install := LDLIBS += -lxml2
-LDFLAGS += -zdefs -zcombreloc
-CFLAGS += -Kpic
-
-POFILES	= $(LINK_SRCS:.c=.po)
-POFILE	= libshare_nfs.po
-
-OWNER= root
-GROUP= sys
-FILEMODE= 555
-
-all :=		TARGET= all
-install :=	TARGET= install
-clean :=	TARGET= clean
-clobber :=	TARGET= clobber
-lint :=		TARGET= lint
-
-
-.KEEP_STATE:
-
-all: $(MODS)
-
-install: all \
-	$(ROOTLIB_NFS_LINKMOD) \
-	$(ROOTLIB_NFS_LINK_MODS)
-
-%.so: %.o
-	$(LINK.c) -o $@ $(GSHARED) -h $@ $<
-
-%.o: $(COMMON)/%.c
-	$(COMPILE.c) -o $@ $<
-
-$(NFS_MOD): $(NFS_OBJS)
-	$(LINK.c) -o $@ $(GSHARED) $(LDLIBS) -h $@ $(NFS_OBJS)
-	$(POST_PROCESS)
-
-clean:
-	$(RM) $(OBJS) 
-
-lint: $(LINT_MODULES)
-
-%.ln: FRC
-	$(LINT.c) $(@:.ln=.c) $(LDLIBS)
-
-FRC:
-
-include ../../../../Makefile.targ
-
-$(POFILE):      $(POFILES)
-	$(RM) $@; cat $(POFILES) > $@
-
-$(ROOTLIB_NFS):
-	$(INS.dir)
-
-$(ROOTLIB_NFS_LINKMOD):
-	$(INS.dir)
-
-$(ROOTLIB_NFS_LINKMOD)/%.so: %.so
-	$(INS.file)
-
-%.o:	$(NFSLIB_DIR)/%.c
-	$(COMPILE.c) $(OUTPUT_OPTION) $< $(CTFCONVERT_HOOK)
-	$(POST_PROCESS_O)
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/i386/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-
-install: all
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.c	Wed Mar 28 07:55:32 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2696 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * NFS specific functions
- */
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <zone.h>
-#include <errno.h>
-#include <locale.h>
-#include <signal.h>
-#include "libshare.h"
-#include "libshare_impl.h"
-#include <nfs/export.h>
-#include <pwd.h>
-#include <limits.h>
-#include <libscf.h>
-#include "nfslog_config.h"
-#include "nfslogtab.h"
-#include "libshare_nfs.h"
-#include <rpcsvc/daemon_utils.h>
-#include <nfs/nfs.h>
-
-/* should really be in some global place */
-#define	DEF_WIN	30000
-#define	OPT_CHUNK	1024
-
-int debug = 0;
-
-
-/* internal functions */
-static int nfs_init();
-static void nfs_fini();
-static int nfs_enable_share(sa_share_t);
-static int nfs_disable_share(char *);
-static int nfs_validate_property(sa_property_t, sa_optionset_t);
-static int nfs_validate_security_mode(char *);
-static int nfs_is_security_opt(char *);
-static int nfs_parse_legacy_options(sa_group_t, char *);
-static char *nfs_format_options(sa_group_t, int);
-static int nfs_set_proto_prop(sa_property_t);
-static sa_protocol_properties_t nfs_get_proto_set();
-static char *nfs_get_status();
-static char *nfs_space_alias(char *);
-
-/*
- * ops vector that provides the protocol specific info and operations
- * for share management.
- */
-
-struct sa_plugin_ops sa_plugin_ops = {
-	SA_PLUGIN_VERSION,
-	"nfs",
-	nfs_init,
-	nfs_fini,
-	nfs_enable_share,
-	nfs_disable_share,
-	nfs_validate_property,
-	nfs_validate_security_mode,
-	nfs_is_security_opt,
-	nfs_parse_legacy_options,
-	nfs_format_options,
-	nfs_set_proto_prop,
-	nfs_get_proto_set,
-	nfs_get_status,
-	nfs_space_alias,
-	NULL,
-	NULL
-};
-
-/*
- * list of support services needed
- * defines should come from head/rpcsvc/daemon_utils.h
- */
-
-static char *service_list_default[] =
-	{ STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NULL };
-static char *service_list_logging[] =
-	{ STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, NULL };
-
-/*
- * option definitions.  Make sure to keep the #define for the option
- * index just before the entry it is the index for. Changing the order
- * can cause breakage.  E.g OPT_RW is index 1 and must precede the
- * line that includes the SHOPT_RW and OPT_RW entries.
- */
-
-struct option_defs optdefs[] = {
-#define	OPT_RO		0
-	{SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST},
-#define	OPT_RW		1
-	{SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST},
-#define	OPT_ROOT	2
-	{SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST},
-#define	OPT_SECURE	3
-	{SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED},
-#define	OPT_ANON	4
-	{SHOPT_ANON, OPT_ANON, OPT_TYPE_USER},
-#define	OPT_WINDOW	5
-	{SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER},
-#define	OPT_NOSUID	6
-	{SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN},
-#define	OPT_ACLOK	7
-	{SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN},
-#define	OPT_NOSUB	8
-	{SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN},
-#define	OPT_SEC		9
-	{SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY},
-#define	OPT_PUBLIC	10
-	{SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY},
-#define	OPT_INDEX	11
-	{SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE},
-#define	OPT_LOG		12
-	{SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG},
-#define	OPT_CKSUM	13
-	{SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET},
-#ifdef VOLATILE_FH_TEST	/* XXX added for testing volatile fh's only */
-#define	OPT_VOLFH	14
-	{SHOPT_VOLFH, OPT_VOLFH},
-#endif /* VOLATILE_FH_TEST */
-	NULL
-};
-
-/*
- * list of properties that are related to security flavors.
- */
-static char *seclist[] = {
-	SHOPT_RO,
-	SHOPT_RW,
-	SHOPT_ROOT,
-	SHOPT_WINDOW,
-	NULL
-};
-
-/* structure for list of securities */
-struct securities {
-	sa_security_t security;
-	struct securities *next;
-};
-
-/*
- * findopt(name)
- *
- * Lookup option "name" in the option table and return the table
- * index.
- */
-
-static int
-findopt(char *name)
-{
-	int i;
-	if (name != NULL) {
-	    for (i = 0; optdefs[i].tag != NULL; i++) {
-		if (strcmp(optdefs[i].tag, name) == 0)
-		    return (i);
-	    }
-	}
-	return (-1);
-}
-
-/*
- * gettype(name)
- *
- * Return the type of option "name".
- */
-
-static int
-gettype(char *name)
-{
-	int optdef;
-
-	optdef = findopt(name);
-	if (optdef != -1)
-	    return (optdefs[optdef].type);
-	return (OPT_TYPE_ANY);
-}
-
-/*
- * nfs_validate_security_mode(mode)
- *
- * is the specified mode string a valid one for use with NFS?
- */
-
-static int
-nfs_validate_security_mode(char *mode)
-{
-	seconfig_t secinfo;
-	int err;
-
-	(void) memset(&secinfo, '\0', sizeof (secinfo));
-	err = nfs_getseconfig_byname(mode, &secinfo);
-	if (err == SC_NOERROR)
-	    return (1);
-	return (0);
-}
-
-/*
- * nfs_is_security_opt(tok)
- *
- * check to see if tok represents an option that is only valid in some
- * security flavor.
- */
-
-static int
-nfs_is_security_opt(char *tok)
-{
-	int i;
-
-	for (i = 0; seclist[i] != NULL; i++) {
-	    if (strcmp(tok, seclist[i]) == 0)
-		return (1);
-	}
-	return (0);
-}
-
-/*
- * find_security(seclist, sec)
- *
- * Walk the current list of security flavors and return true if it is
- * present, else return false.
- */
-
-static int
-find_security(struct securities *seclist, sa_security_t sec)
-{
-	while (seclist != NULL) {
-	    if (seclist->security == sec)
-		return (1);
-	    seclist = seclist->next;
-	}
-	return (0);
-}
-
-/*
- * make_security_list(group, securitymodes, proto)
- *	go through the list of securitymodes and add them to the
- *	group's list of security optionsets. We also keep a list of
- *	those optionsets so we don't have to find them later. All of
- *	these will get copies of the same properties.
- */
-
-static struct securities *
-make_security_list(sa_group_t group, char *securitymodes, char *proto)
-{
-	char *tok, *next = NULL;
-	struct securities *curp, *headp = NULL, *prev;
-	sa_security_t check;
-	int freetok = 0;
-
-	for (tok = securitymodes; tok != NULL; tok = next) {
-	    next = strchr(tok, ':');
-	    if (next != NULL)
-		*next++ = '\0';
-	    if (strcmp(tok, "default") == 0) {
-		/* resolve default into the real type */
-		tok = nfs_space_alias(tok);
-		freetok = 1;
-	    }
-	    check = sa_get_security(group, tok, proto);
-
-	    /* add to the security list if it isn't there already */
-	    if (check == NULL || !find_security(headp, check)) {
-		curp = (struct securities *)calloc(1,
-						sizeof (struct securities));
-		if (curp != NULL) {
-		    if (check == NULL) {
-			curp->security = sa_create_security(group, tok,
-								proto);
-		    } else {
-			curp->security = check;
-		    }
-			/*
-			 * note that the first time through the loop,
-			 * headp will be NULL and prev will be
-			 * undefined.  Since headp is NULL, we set
-			 * both it and prev to the curp (first
-			 * structure to be allocated).
-			 *
-			 * later passes through the loop will have
-			 * headp not being NULL and prev will be used
-			 * to allocate at the end of the list.
-			 */
-		    if (headp == NULL) {
-			headp = curp;
-			prev = curp;
-		    } else {
-			prev->next = curp;
-			prev = curp;
-		    }
-		}
-	    }
-
-	    if (freetok) {
-		freetok = 0;
-		sa_free_attr_string(tok);
-	    }
-	}
-	return (headp);
-}
-
-static void
-free_security_list(struct securities *sec)
-{
-	struct securities *next;
-	if (sec != NULL) {
-	    for (next = sec->next; sec != NULL; sec = next) {
-		next = sec->next;
-		free(sec);
-	    }
-	}
-}
-
-/*
- * nfs_alistcat(str1, str2, sep)
- *
- * concatenate str1 and str2 into a new string using sep as a separate
- * character. If memory allocation fails, return NULL;
- */
-
-static char *
-nfs_alistcat(char *str1, char *str2, char sep)
-{
-	char *newstr;
-	size_t len;
-
-	len = strlen(str1) + strlen(str2) + 2;
-	newstr = (char *)malloc(len);
-	if (newstr != NULL)
-	    (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2);
-	return (newstr);
-}
-
-/*
- * add_security_prop(sec, name, value, persist)
- *
- * Add the property to the securities structure. This accumulates
- * properties for as part of parsing legacy options.
- */
-
-static int
-add_security_prop(struct securities *sec, char *name, char *value,
-			int persist, int iszfs)
-{
-	sa_property_t prop;
-	int ret = SA_OK;
-
-	for (; sec != NULL; sec = sec->next) {
-	    if (value == NULL) {
-		if (strcmp(name, SHOPT_RW) == 0 || strcmp(name, SHOPT_RO) == 0)
-		    value = "*";
-		else
-		    value = "true";
-	    }
-
-		/*
-		 * Get the existing property, if it exists, so we can
-		 * determine what to do with it. The ro/rw/root
-		 * properties can be merged if multiple instances of
-		 * these properies are given. For example, if "rw"
-		 * exists with a value "host1" and a later token of
-		 * rw="host2" is seen, the values are merged into a
-		 * single rw="host1:host2".
-		 */
-	    prop = sa_get_property(sec->security, name);
-
-	    if (prop != NULL) {
-		char *oldvalue;
-		char *newvalue;
-
-		/*
-		 * The security options of ro/rw/root might appear
-		 * multiple times. If they do, the values need to be
-		 * merged into an access list. If it was previously
-		 * empty, the new value alone is added.
-		 */
-		oldvalue = sa_get_property_attr(prop, "value");
-		if (oldvalue != NULL) {
-			/*
-			 * The general case is to concatenate the new
-			 * value onto the old value for multiple
-			 * rw(ro/root) properties. A special case
-			 * exists when either the old or new is the
-			 * "all" case. In the special case, if both
-			 * are "all", then it is "all", else if one is
-			 * an access-list, that replaces the "all".
-			 */
-		    if (strcmp(oldvalue, "*") == 0) {
-			/* Replace old value with new value. */
-			newvalue = strdup(value);
-		    } else if (strcmp(value, "*") == 0) {
-			/* Keep old value and ignore the new value. */
-			newvalue = NULL;
-		    } else {
-			/* Make a new list of old plus new access-list. */
-			newvalue = nfs_alistcat(oldvalue, value, ':');
-		    }
-
-		    if (newvalue != NULL) {
-			(void) sa_remove_property(prop);
-			prop = sa_create_property(name, newvalue);
-			ret = sa_add_property(sec->security, prop);
-			free(newvalue);
-		    }
-		    if (oldvalue != NULL)
-			sa_free_attr_string(oldvalue);
-		}
-	    } else {
-		prop = sa_create_property(name, value);
-		ret = sa_add_property(sec->security, prop);
-	    }
-	    if (ret == SA_OK && !iszfs) {
-		ret = sa_commit_properties(sec->security, !persist);
-	    }
-	}
-	return (ret);
-}
-
-/*
- * check to see if group/share is persistent.
- */
-static int
-is_persistent(sa_group_t group)
-{
-	char *type;
-	int persist = 1;
-
-	type = sa_get_group_attr(group, "type");
-	if (type != NULL && strcmp(type, "persist") != 0)
-	    persist = 0;
-	if (type != NULL)
-	    sa_free_attr_string(type);
-	return (persist);
-}
-
-/*
- * invalid_security(options)
- *
- * search option string for any invalid sec= type.
- * return true (1) if any are not valid else false (0)
- */
-static int
-invalid_security(char *options)
-{
-	char *copy, *base, *token, *value;
-	int ret = 0;
-
-	copy = strdup(options);
-	token = base = copy;
-	while (token != NULL && ret == 0) {
-	    token = strtok(base, ",");
-	    base = NULL;
-	    if (token != NULL) {
-		value = strchr(token, '=');
-		if (value != NULL)
-		    *value++ = '\0';
-		if (strcmp(token, "sec") == 0) {
-		    /* have security flavors so check them */
-		    char *tok, *next;
-		    for (next = NULL, tok = value; tok != NULL; tok = next) {
-			next = strchr(tok, ':');
-			if (next != NULL)
-			    *next++ = '\0';
-			ret = !nfs_validate_security_mode(tok);
-			if (ret)
-			    break;
-		    }
-		}
-	    }
-	}
-	if (copy != NULL)
-	    free(copy);
-	return (ret);
-}
-
-/*
- * nfs_parse_legacy_options(group, options)
- *
- * Parse the old style options into internal format and store on the
- * specified group.  Group could be a share for full legacy support.
- */
-
-static int
-nfs_parse_legacy_options(sa_group_t group, char *options)
-{
-	char *dup = strdup(options);
-	char *base;
-	char *token;
-	sa_optionset_t optionset;
-	struct securities *security_list = NULL;
-	sa_property_t prop;
-	int ret = SA_OK;
-	int iszfs = 0;
-	sa_group_t parent;
-	int persist = 0;
-	char *lasts;
-
-	/* do we have an existing optionset? */
-	optionset = sa_get_optionset(group, "nfs");
-	if (optionset == NULL) {
-	    /* didn't find existing optionset so create one */
-	    optionset = sa_create_optionset(group, "nfs");
-	} else {
-		/*
-		 * have an existing optionset so we need to compare
-		 * options in order to detect errors. For now, we
-		 * assume that the first optionset is the correct one
-		 * and the others will be the same. This needs to be
-		 * fixed before the final code is ready.
-		 */
-	    return (ret);
-	}
-
-	if (strcmp(options, SHOPT_RW) == 0) {
-		/*
-		 * there is a special case of only the option "rw"
-		 * being the default option. We don't have to do
-		 * anything.
-		 */
-	    return (ret);
-	}
-
-	/*
-	 * check if security types are present and validate them. If
-	 * any are not legal, fail.
-	 */
-
-	if (invalid_security(options)) {
-	    return (SA_INVALID_SECURITY);
-	}
-
-	/*
-	 * in order to not attempt to change ZFS properties unless
-	 * absolutely necessary, we never do it in the legacy parsing.
-	 */
-	if (sa_is_share(group)) {
-	    char *zfs;
-	    parent = sa_get_parent_group(group);
-	    if (parent != NULL) {
-		zfs = sa_get_group_attr(parent, "zfs");
-		if (zfs != NULL) {
-		    sa_free_attr_string(zfs);
-		    iszfs++;
-		}
-	    }
-	} else {
-	    iszfs = sa_group_is_zfs(group);
-	}
-
-	/*
-	 * we need to step through each option in the string and then
-	 * add either the option or the security option as needed. If
-	 * this is not a persistent share, don't commit to the
-	 * repository. If there is an error, we also want to abort the
-	 * processing and report it.
-	 */
-	persist = is_persistent(group);
-	base = dup;
-	token = dup;
-	lasts = NULL;
-	while (token != NULL && ret == SA_OK) {
-	    ret = SA_OK;
-	    token = strtok_r(base, ",", &lasts);
-	    base = NULL;
-	    if (token != NULL) {
-		char *value;
-		/*
-		 * if the option has a value, it will have an '=' to
-		 * separate the name from the value. The following
-		 * code will result in value != NULL and token
-		 * pointing to just the name if there is a value.
-		 */
-		value = strchr(token, '=');
-		if (value != NULL) {
-		    *value++ = '\0';
-		}
-		if (strcmp(token, "sec") == 0 || strcmp(token, "secure") == 0) {
-			/*
-			 * Once in security parsing, we only
-			 * do security. We do need to move
-			 * between the security node and the
-			 * toplevel. The security tag goes on
-			 * the root while the following ones
-			 * go on the security.
-			 */
-		    if (security_list != NULL) {
-			/* have an old list so close it and start the new */
-			free_security_list(security_list);
-		    }
-		    if (strcmp(token, "secure") == 0) {
-			value = "dh";
-		    } else {
-			if (value == NULL) {
-			    ret = SA_SYNTAX_ERR;
-			    break;
-			}
-		    }
-		    security_list = make_security_list(group, value, "nfs");
-		} else {
-			/*
-			 * Note that the "old" syntax allowed a
-			 * default security model This must be
-			 * accounted for and internally converted to
-			 * "standard" security structure.
-			 */
-		    if (nfs_is_security_opt(token)) {
-			if (security_list == NULL) {
-				/*
-				 * need to have a security option. This
-				 * will be "closed" when a defined "sec="
-				 * option is seen. This is technically an
-				 * error but will be allowed with warning.
-				 */
-			    security_list = make_security_list(group,
-								"default",
-								"nfs");
-			}
-			if (security_list != NULL) {
-			    ret = add_security_prop(security_list, token,
-							value, persist,
-							iszfs);
-			} else {
-			    ret = SA_NO_MEMORY;
-			}
-		    } else {
-			/* regular options */
-			if (value == NULL) {
-			    if (strcmp(token, SHOPT_RW) == 0 ||
-				strcmp(token, SHOPT_RO) == 0)
-				value = "*";
-			    else if (strcmp(token, SHOPT_LOG) == 0)
-				value = "global";
-			    else
-				value = "true";
-			}
-			prop = sa_create_property(token, value);
-			ret = sa_add_property(optionset, prop);
-			if (ret != SA_OK) {
-			    break;
-			}
-			if (!iszfs) {
-			    ret = sa_commit_properties(optionset, !persist);
-			}
-		    }
-		}
-	    }
-	}
-	if (security_list != NULL)
-	    free_security_list(security_list);
-	if (dup != NULL)
-	    free(dup);
-	return (ret);
-}
-
-/*
- * is_a_number(number)
- *
- * is the string a number in one of the forms we want to use?
- */
-
-static int
-is_a_number(char *number)
-{
-	int ret = 1;
-	int hex = 0;
-
-	if (strncmp(number, "0x", 2) == 0) {
-	    number += 2;
-	    hex = 1;
-	} else if (*number == '-')
-	    number++; /* skip the minus */
-
-	while (ret == 1 && *number != '\0') {
-	    if (hex) {
-		ret = isxdigit(*number++);
-	    } else {
-		ret = isdigit(*number++);
-	    }
-	}
-	return (ret);
-}
-
-/*
- * Look for the specified tag in the configuration file. If it is found,
- * enable logging and set the logging configuration information for exp.
- */
-static void
-configlog(struct exportdata *exp, char *tag)
-{
-	nfsl_config_t *configlist = NULL, *configp;
-	int error = 0;
-	char globaltag[] = DEFAULTTAG;
-
-	/*
-	 * Sends config errors to stderr
-	 */
-	nfsl_errs_to_syslog = B_FALSE;
-
-	/*
-	 * get the list of configuration settings
-	 */
-	error = nfsl_getconfig_list(&configlist);
-	if (error) {
-		(void) fprintf(stderr,
-				gettext("Cannot get log configuration: %s\n"),
-				strerror(error));
-	}
-
-	if (tag == NULL)
-		tag = globaltag;
-	if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) {
-		nfsl_freeconfig_list(&configlist);
-		(void) fprintf(stderr,
-				gettext("No tags matching \"%s\"\n"), tag);
-		/* bad configuration */
-		error = ENOENT;
-		goto err;
-	}
-
-	if ((exp->ex_tag = strdup(tag)) == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-	if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-	exp->ex_flags |= EX_LOG;
-	if (configp->nc_rpclogpath != NULL)
-		exp->ex_flags |= EX_LOG_ALLOPS;
-out:
-	if (configlist != NULL)
-	    nfsl_freeconfig_list(&configlist);
-
-err:
-	if (error != 0) {
-		if (exp->ex_flags != NULL)
-			free(exp->ex_tag);
-		if (exp->ex_log_buffer != NULL)
-			free(exp->ex_log_buffer);
-		(void) fprintf(stderr,
-				gettext("Cannot set log configuration: %s\n"),
-				strerror(error));
-	}
-}
-
-/*
- * fill_export_from_optionset(export, optionset)
- *
- * In order to share, we need to set all the possible general options
- * into the export structure. Share info will be filled in by the
- * caller. Various property values get turned into structure specific
- * values.
- */
-
-static int
-fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
-{
-	sa_property_t option;
-	int ret = SA_OK;
-
-	for (option = sa_get_property(optionset, NULL);
-		option != NULL; option = sa_get_next_property(option)) {
-	    char *name;
-	    char *value;
-	    uint32_t val;
-
-	/*
-	 * since options may be set/reset multiple times, always do an
-	 * explicit set or clear of the option. This allows defaults
-	 * to be set and then the protocol specifici to override.
-	 */
-
-	    name = sa_get_property_attr(option, "type");
-	    value = sa_get_property_attr(option, "value");
-	    switch (findopt(name)) {
-	    case OPT_ANON:
-		if (value != NULL && is_a_number(value)) {
-		    val = strtoul(value, NULL, 0);
-		} else {
-		    struct passwd *pw;
-		    pw = getpwnam(value != NULL ? value : "nobody");
-		    if (pw != NULL) {
-			val = pw->pw_uid;
-		    } else {
-			val = UID_NOBODY;
-		    }
-		    endpwent();
-		}
-		export->ex_anon = val;
-		break;
-	    case OPT_NOSUID:
-		if (value != NULL &&
-		    (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0))
-		    export->ex_flags |= EX_NOSUID;
-		else
-		    export->ex_flags &= ~EX_NOSUID;
-		break;
-	    case OPT_ACLOK:
-		if (value != NULL &&
-		    (strcasecmp(value, "true") == 0 ||
-			strcmp(value, "1") == 0))
-		    export->ex_flags |= EX_ACLOK;
-		else
-		    export->ex_flags &= ~EX_ACLOK;
-		break;
-	    case OPT_NOSUB:
-		if (value != NULL &&
-		    (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0))
-		    export->ex_flags |= EX_NOSUB;
-		else
-		    export->ex_flags &= ~EX_NOSUB;
-		break;
-	    case OPT_PUBLIC:
-		if (value != NULL &&
-		    (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0))
-		    export->ex_flags |= EX_PUBLIC;
-		else
-		    export->ex_flags &= ~EX_PUBLIC;
-		break;
-	    case OPT_INDEX:
-		if (value != NULL &&
-		    (strcmp(value, "..") == 0 || strchr(value, '/') != NULL)) {
-		    /* this is an error */
-		    (void) printf(gettext("NFS: index=\"%s\" not valid;"
-					    "must be a filename.\n"),
-			    value);
-		    break;
-		}
-		if (value != NULL && *value != '\0' &&
-			strcmp(value, ".") != 0) {
-		    /* valid index file string */
-		    if (export->ex_index != NULL) {
-			/* left over from "default" */
-			free(export->ex_index);
-		    }
-		    export->ex_index = strdup(value); /* remember to free */
-		    if (export->ex_index == NULL) {
-			(void) printf(gettext("NFS: out of memory setting "
-						"index property\n"));
-			break;
-		    }
-		    export->ex_flags |= EX_INDEX;
-		}
-		break;
-	    case OPT_LOG:
-		if (value == NULL)
-		    value = strdup("global");
-		if (value != NULL)
-		    configlog(export, strlen(value) ? value : "global");
-		break;
-	    case OPT_CKSUM:
-		/* TBD: not ready yet */
-		break;
-	    default:
-		/* have a syntactic error */
-		(void) printf(gettext("NFS: unrecognized option %s=%s\n"),
-			name, value != NULL ? value : "");
-		break;
-	    }
-	    if (name != NULL)
-		sa_free_attr_string(name);
-	    if (value != NULL)
-		sa_free_attr_string(value);
-	}
-	return (ret);
-}
-
-/*
- * cleanup_export(export)
- *
- * Cleanup the allocated areas so we don't leak memory
- */
-
-static void
-cleanup_export(struct exportdata *export)
-{
-	int i;
-
-	if (export->ex_index != NULL)
-	    free(export->ex_index);
-	if (export->ex_secinfo != NULL) {
-	    for (i = 0; i < export->ex_seccnt; i++)
-		if (export->ex_secinfo[i].s_rootnames != NULL) {
-		    free(export->ex_secinfo[i].s_rootnames);
-		}
-	    free(export->ex_secinfo);
-	}
-}
-
-/*
- * Given a seconfig entry and a colon-separated
- * list of names, allocate an array big enough
- * to hold the root list, then convert each name to
- * a principal name according to the security
- * info and assign it to an array element.
- * Return the array and its size.
- */
-static caddr_t *
-get_rootnames(seconfig_t *sec, char *list, int *count)
-{
-	caddr_t *a;
-	int c, i;
-	char *host, *p;
-
-	/*
-	 * Count the number of strings in the list.
-	 * This is the number of colon separators + 1.
-	 */
-	c = 1;
-	for (p = list; *p; p++)
-		if (*p == ':')
-			c++;
-	*count = c;
-
-	a = (caddr_t *)malloc(c * sizeof (char *));
-	if (a == NULL) {
-		(void) printf(gettext("get_rootnames: no memory\n"));
-	} else {
-	    for (i = 0; i < c; i++) {
-		host = strtok(list, ":");
-		if (!nfs_get_root_principal(sec, host, &a[i])) {
-		    free(a);
-		    a = NULL;
-		    break;
-		}
-		list = NULL;
-	    }
-	}
-
-	return (a);
-}
-
-/*
- * fill_security_from_secopts(sp, secopts)
- *
- * Fill the secinfo structure from the secopts optionset.
- */
-
-static int
-fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts)
-{
-	sa_property_t prop;
-	char *type;
-	int longform;
-	int err = SC_NOERROR;
-
-	type = sa_get_security_attr(secopts, "sectype");
-	if (type != NULL) {
-	    /* named security type needs secinfo to be filled in */
-	    err = nfs_getseconfig_byname(type, &sp->s_secinfo);
-	    sa_free_attr_string(type);
-	    if (err != SC_NOERROR)
-		return (err);
-	} else {
-	    /* default case */
-	    err = nfs_getseconfig_default(&sp->s_secinfo);
-	    if (err != SC_NOERROR)
-		return (err);
-	}
-
-	err = SA_OK;
-	for (prop = sa_get_property(secopts, NULL);
-		prop != NULL && err == SA_OK;
-		prop = sa_get_next_property(prop)) {
-	    char *name;
-	    char *value;
-
-	    name = sa_get_property_attr(prop, "type");
-	    value = sa_get_property_attr(prop, "value");
-
-	    longform = value != NULL && strcmp(value, "*") != 0;
-
-	    switch (findopt(name)) {
-	    case OPT_RO:
-		sp->s_flags |= longform ? M_ROL : M_RO;
-		break;
-	    case OPT_RW:
-		sp->s_flags |= longform ? M_RWL : M_RW;
-		break;
-	    case OPT_ROOT:
-		sp->s_flags |= M_ROOT;
-		/*
-		 * if we are using AUTH_UNIX, handle like other things
-		 * such as RO/RW
-		 */
-		if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX)
-		    continue;
-		/* not AUTH_UNIX */
-		if (value != NULL) {
-		    sp->s_rootnames = get_rootnames(&sp->s_secinfo, value,
-							&sp->s_rootcnt);
-		    if (sp->s_rootnames == NULL) {
-			err = SA_BAD_VALUE;
-			(void) fprintf(stderr, gettext("Bad root list\n"));
-		    }
-		}
-		break;
-	    case OPT_WINDOW:
-		if (value != NULL) {
-		    sp->s_window = atoi(value);
-		    if (sp->s_window < 0)
-			sp->s_window = DEF_WIN; /* just in case */
-		}
-		break;
-	    default:
-		break;
-	    }
-	    if (name != NULL)
-		sa_free_attr_string(name);
-	    if (value != NULL)
-		sa_free_attr_string(value);
-	}
-	/* if rw/ro options not set, use default of RW */
-	if ((sp->s_flags & NFS_RWMODES) == 0)
-	    sp->s_flags |= M_RW;
-	return (err);
-}
-
-/*
- * This is for testing only
- * It displays the export structure that
- * goes into the kernel.
- */
-static void
-printarg(char *path, struct exportdata *ep)
-{
-	int i, j;
-	struct secinfo *sp;
-
-	if (debug == 0)
-	    return;
-
-	(void) printf("%s:\n", path);
-	(void) printf("\tex_version = %d\n", ep->ex_version);
-	(void) printf("\tex_path = %s\n", ep->ex_path);
-	(void) printf("\tex_pathlen = %d\n", ep->ex_pathlen);
-	(void) printf("\tex_flags: (0x%02x) ", ep->ex_flags);
-	if (ep->ex_flags & EX_NOSUID)
-		(void) printf("NOSUID ");
-	if (ep->ex_flags & EX_ACLOK)
-		(void) printf("ACLOK ");
-	if (ep->ex_flags & EX_PUBLIC)
-		(void) printf("PUBLIC ");
-	if (ep->ex_flags & EX_NOSUB)
-		(void) printf("NOSUB ");
-	if (ep->ex_flags & EX_LOG)
-		(void) printf("LOG ");
-	if (ep->ex_flags & EX_LOG_ALLOPS)
-		(void) printf("LOG_ALLOPS ");
-	if (ep->ex_flags == 0)
-		(void) printf("(none)");
-	(void) 	printf("\n");
-	if (ep->ex_flags & EX_LOG) {
-		(void) printf("\tex_log_buffer = %s\n",
-			(ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)"));
-		(void) printf("\tex_tag = %s\n",
-				(ep->ex_tag ? ep->ex_tag : "(NULL)"));
-	}
-	(void) printf("\tex_anon = %d\n", ep->ex_anon);
-	(void) printf("\tex_seccnt = %d\n", ep->ex_seccnt);
-	(void) printf("\n");
-	for (i = 0; i < ep->ex_seccnt; i++) {
-		sp = &ep->ex_secinfo[i];
-		(void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name);
-		(void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags);
-		if (sp->s_flags & M_ROOT) (void) printf("M_ROOT ");
-		if (sp->s_flags & M_RO) (void) printf("M_RO ");
-		if (sp->s_flags & M_ROL) (void) printf("M_ROL ");
-		if (sp->s_flags & M_RW) (void) printf("M_RW ");
-		if (sp->s_flags & M_RWL) (void) printf("M_RWL ");
-		if (sp->s_flags == 0) (void) printf("(none)");
-		(void) printf("\n");
-		(void) printf("\t\ts_window = %d\n", sp->s_window);
-		(void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt);
-		(void) fflush(stdout);
-		for (j = 0; j < sp->s_rootcnt; j++)
-			(void) printf("%s ", sp->s_rootnames[j] ?
-					sp->s_rootnames[j] : "<null>");
-		(void) printf("\n\n");
-	}
-}
-
-/*
- * count_security(opts)
- *
- * Count the number of security types (flavors). The optionset has
- * been populated with the security flavors as a holding mechanism.
- * We later use this number to allocate data structures.
- */
-
-static int
-count_security(sa_optionset_t opts)
-{
-	int count = 0;
-	sa_property_t prop;
-	if (opts != NULL) {
-	    for (prop = sa_get_property(opts, NULL); prop != NULL;
-		prop = sa_get_next_property(prop)) {
-		count++;
-	    }
-	}
-	return (count);
-}
-
-/*
- * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep)
- *
- * provides a mechanism to format NFS properties into legacy output
- * format. If the buffer would overflow, it is reallocated and grown
- * as appropriate. Special cases of converting internal form of values
- * to those used by "share" are done. this function does one property
- * at a time.
- */
-
-static void
-nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
-			sa_property_t prop, int sep)
-{
-	char *name;
-	char *value;
-	int curlen;
-	char *buff = *rbuff;
-	size_t buffsize = *rbuffsize;
-
-	name = sa_get_property_attr(prop, "type");
-	value = sa_get_property_attr(prop, "value");
-	if (buff != NULL)
-	    curlen = strlen(buff);
-	else
-	    curlen = 0;
-	if (name != NULL) {
-	    int len;
-	    len = strlen(name) + sep;
-
-		/*
-		 * A future RFE would be to replace this with more
-		 * generic code and to possibly handle more types.
-		 */
-	    switch (gettype(name)) {
-	    case OPT_TYPE_BOOLEAN:
-		if (value != NULL && strcasecmp(value, "false") == 0) {
-		    *name = '\0';
-		}
-		if (value != NULL)
-		    sa_free_attr_string(value);
-		value = NULL;
-		break;
-	    case OPT_TYPE_ACCLIST:
-		if (value != NULL && strcmp(value, "*") == 0) {
-		    sa_free_attr_string(value);
-		    value = NULL;
-		} else {
-		    if (value != NULL)
-			len += 1 + strlen(value);
-		}
-		break;
-	    case OPT_TYPE_LOGTAG:
-		if (value != NULL && strlen(value) == 0) {
-		    sa_free_attr_string(value);
-		    value = NULL;
-		} else {
-		    if (value != NULL)
-			len += 1 + strlen(value);
-		}
-		break;
-	    default:
-		if (value != NULL)
-		    len += 1 + strlen(value);
-		break;
-	    }
-	    while (buffsize <= (curlen + len)) {
-		/* need more room */
-		buffsize += incr;
-		buff = realloc(buff, buffsize);
-		if (buff == NULL) {
-		    /* realloc failed so free everything */
-		    if (*rbuff != NULL)
-			free(*rbuff);
-		}
-		*rbuff = buff;
-		*rbuffsize = buffsize;
-		if (buff == NULL) {
-		    return;
-		}
-	    }
-	    if (buff == NULL)
-		return;
-	    if (value == NULL)
-		(void) snprintf(buff + curlen, buffsize - curlen,
-				"%s%s", sep ? "," : "",
-				name, value != NULL ? value : "");
-	    else
-		(void) snprintf(buff + curlen, buffsize - curlen,
-				"%s%s=%s", sep ? "," : "",
-				name, value != NULL ? value : "");
-	}
-	if (name != NULL)
-	    sa_free_attr_string(name);
-	if (value != NULL)
-	    sa_free_attr_string(value);
-}
-
-/*
- * nfs_format_options(group, hier)
- *
- * format all the options on the group into an old-style option
- * string. If hier is non-zero, walk up the tree to get inherited
- * options.
- */
-
-static char *
-nfs_format_options(sa_group_t group, int hier)
-{
-	sa_optionset_t options = NULL;
-	sa_optionset_t secoptions;
-	sa_property_t prop, secprop;
-	sa_security_t security;
-	char *buff;
-	size_t buffsize;
-
-	options = sa_get_derived_optionset(group, "nfs", hier);
-
-	/*
-	 * have a an optionset relative to this item, if any. format
-	 * these then add any security definitions.
-	 */
-	buff = malloc(OPT_CHUNK);
-	if (buff != NULL) {
-	    int sep = 0;
-	    buff[0] = '\0';
-	    buffsize = OPT_CHUNK;
-		/*
-		 * do the default set first but skip any option that is also
-		 * in the protocol specific optionset.
-		 */
-	    if (options != NULL) {
-		for (prop = sa_get_property(options, NULL); prop != NULL;
-			prop = sa_get_next_property(prop)) {
-			/*
-			 * use this one since we skipped any of these that
-			 * were also in optdefault
-			 */
-		    nfs_sprint_option(&buff, &buffsize, OPT_CHUNK, prop, sep);
-		    if (buff == NULL) {
-			/*
-			 * buff could become NULL if there isn't
-			 * enough memory for nfs_sprint_option to
-			 * realloc() as necessary. We can't really do
-			 * anything about it at this point so we
-			 * return NULL.  The caller should handle the
-			 * failure. Note that this
-			 */
-			return (buff);
-		    }
-		    sep = 1;
-		}
-	    }
-	    secoptions = (sa_optionset_t)sa_get_all_security_types(group,
-								"nfs", hier);
-	    if (secoptions != NULL) {
-		for (secprop = sa_get_property(secoptions, NULL);
-		    secprop != NULL; secprop = sa_get_next_property(secprop)) {
-		    char *sectype;
-
-		    sectype = sa_get_property_attr(secprop, "type");
-		    security = (sa_security_t)sa_get_derived_security(group,
-								sectype,
-								"nfs", hier);
-		    if (security != NULL) {
-			if (sectype != NULL) {
-			    prop = sa_create_property("sec", sectype);
-			    nfs_sprint_option(&buff, &buffsize, OPT_CHUNK,
-						prop, sep);
-			    (void) sa_remove_property(prop);
-			sep = 1;
-			}
-			for (prop = sa_get_property(security, NULL);
-			    prop != NULL;
-			    prop = sa_get_next_property(prop)) {
-
-			    nfs_sprint_option(&buff, &buffsize, OPT_CHUNK,
-						prop, sep);
-			    if (buff == NULL) {
-				/* catastrophic memory failure */
-				sa_free_derived_optionset(secoptions);
-				if (security != NULL)
-				    sa_free_derived_optionset(security);
-				if (sectype != NULL)
-				    sa_free_attr_string(sectype);
-				if (options != NULL)
-				    sa_free_derived_optionset(options);
-				return (buff);
-			    }
-			    sep = 1;
-			}
-			sa_free_derived_optionset(security);
-		    }
-		    if (sectype != NULL)
-			sa_free_attr_string(sectype);
-		}
-		sa_free_derived_optionset(secoptions);
-	    }
-	}
-	if (options != NULL)
-	    sa_free_derived_optionset(options);
-	return (buff);
-}
-/*
- * Append an entry to the nfslogtab file
- */
-static int
-nfslogtab_add(dir, buffer, tag)
-	char *dir, *buffer, *tag;
-{
-	FILE *f;
-	struct logtab_ent lep;
-	int error = 0;
-
-	/*
-	 * Open the file for update and create it if necessary.
-	 * This may leave the I/O offset at the end of the file,
-	 * so rewind back to the beginning of the file.
-	 */
-	f = fopen(NFSLOGTAB, "a+");
-	if (f == NULL) {
-		error = errno;
-		goto out;
-	}
-	rewind(f);
-
-	if (lockf(fileno(f), F_LOCK, 0L) < 0) {
-		(void) fprintf(stderr, gettext(
-			"share complete, however failed to lock %s "
-			"for update: %s\n"), NFSLOGTAB, strerror(errno));
-		error = -1;
-		goto out;
-	}
-
-	if (logtab_deactivate_after_boot(f) == -1) {
-		(void) fprintf(stderr, gettext(
-			"share complete, however could not deactivate "
-			"entries in %s\n"), NFSLOGTAB);
-		error = -1;
-		goto out;
-	}
-
-	/*
-	 * Remove entries matching buffer and sharepoint since we're
-	 * going to replace it with perhaps an entry with a new tag.
-	 */
-	if (logtab_rement(f, buffer, dir, NULL, -1)) {
-		(void) fprintf(stderr, gettext(
-			"share complete, however could not remove matching "
-			"entries in %s\n"), NFSLOGTAB);
-		error = -1;
-		goto out;
-	}
-
-	/*
-	 * Deactivate all active entries matching this sharepoint
-	 */
-	if (logtab_deactivate(f, NULL, dir, NULL)) {
-		(void) fprintf(stderr, gettext(
-			"share complete, however could not deactivate matching "
-			"entries in %s\n"), NFSLOGTAB);
-		error = -1;
-		goto out;
-	}
-
-	lep.le_buffer = buffer;
-	lep.le_path = dir;
-	lep.le_tag = tag;
-	lep.le_state = LES_ACTIVE;
-
-	/*
-	 * Add new sharepoint / buffer location to nfslogtab
-	 */
-	if (logtab_putent(f, &lep) < 0) {
-		(void) fprintf(stderr, gettext(
-			"share complete, however could not add %s to %s\n"),
-			dir, NFSLOGTAB);
-		error = -1;
-	}
-
-out:
-	if (f != NULL)
-		(void) fclose(f);
-	return (error);
-}
-
-/*
- * Deactivate an entry from the nfslogtab file
- */
-static int
-nfslogtab_deactivate(path)
-	char *path;
-{
-	FILE *f;
-	int error = 0;
-
-	f = fopen(NFSLOGTAB, "r+");
-	if (f == NULL) {
-		error = errno;
-		goto out;
-	}
-	if (lockf(fileno(f), F_LOCK, 0L) < 0) {
-		error = errno;
-		(void)  fprintf(stderr, gettext(
-			"share complete, however could not lock %s for "
-			"update: %s\n"), NFSLOGTAB, strerror(error));
-		goto out;
-	}
-	if (logtab_deactivate(f, NULL, path, NULL) == -1) {
-		error = -1;
-		(void) fprintf(stderr,
-			gettext("share complete, however could not "
-			"deactivate %s in %s\n"), path, NFSLOGTAB);
-		goto out;
-	}
-
-out:	if (f != NULL)
-		(void) fclose(f);
-
-	return (error);
-}
-
-/*
- * public_exists(share)
- *
- * check to see if public option is set on any other share than the
- * one specified.
- */
-static int
-public_exists(sa_share_t skipshare)
-{
-	sa_share_t share;
-	sa_group_t group;
-	sa_optionset_t opt;
-	sa_property_t prop;
-	int exists = 0;
-
-	for (group = sa_get_group(NULL); group != NULL;
-	    group = sa_get_next_group(group)) {
-	    for (share = sa_get_share(group, NULL); share != NULL;
-		share = sa_get_next_share(share)) {
-		if (share == skipshare)
-		    continue;
-		opt = sa_get_optionset(share, "nfs");
-		if (opt != NULL) {
-		    prop = sa_get_property(opt, "public");
-		    if (prop != NULL) {
-			char *shared;
-			shared = sa_get_share_attr(share, "shared");
-			if (shared != NULL) {
-			    exists = strcmp(shared, "true") == 0;
-			    sa_free_attr_string(shared);
-			    goto out;
-			}
-		    }
-		}
-	    }
-	}
-out:
-	return (exists);
-}
-
-/*
- * sa_enable_share at the protocol level, enable_share must tell the
- * implementation that it is to enable the share. This entails
- * converting the path and options into the appropriate ioctl
- * calls. It is assumed that all error checking of paths, etc. were
- * done earlier.
- */
-static int
-nfs_enable_share(sa_share_t share)
-{
-	struct exportdata export;
-	sa_optionset_t secoptlist;
-	struct secinfo *sp;
-	int num_secinfo;
-	sa_optionset_t opt;
-	sa_security_t sec;
-	sa_property_t prop;
-	char *path;
-	int err = SA_OK;
-
-	/* Don't drop core if the NFS module isn't loaded. */
-	(void) signal(SIGSYS, SIG_IGN);
-
-	/* get the path since it is important in several places */
-	path = sa_get_share_attr(share, "path");
-	if (path == NULL)
-	    return (SA_NO_SUCH_PATH);
-
-	/*
-	 * find the optionsets and security sets.  There may not be
-	 * any or there could be one or two for each of optionset and
-	 * security may have multiple, one per security type per
-	 * protocol type.
-	 */
-	opt = sa_get_derived_optionset(share, "nfs", 1);
-	secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1);
-	if (secoptlist != NULL)
-	    num_secinfo = MAX(1, count_security(secoptlist));
-	else
-	    num_secinfo = 1;
-
-	/*
-	 * walk through the options and fill in the structure
-	 * appropriately.
-	 */
-
-	(void) memset(&export, '\0', sizeof (export));
-
-	/*
-	 * do non-security options first since there is only one after
-	 * the derived group is constructed.
-	 */
-	export.ex_version = EX_CURRENT_VERSION;
-	export.ex_anon = UID_NOBODY; /* this is our default value */
-	export.ex_index = NULL;
-	export.ex_path = path;
-	export.ex_pathlen = strlen(path) + 1;
-
-	sp = calloc(num_secinfo, sizeof (struct secinfo));
-
-	if (opt != NULL)
-	    err = fill_export_from_optionset(&export, opt);
-
-	/*
-	 * check to see if "public" is set. If it is, then make sure
-	 * no other share has it set. If it is already used, fail.
-	 */
-
-	if (export.ex_flags & EX_PUBLIC && public_exists(share)) {
-	    (void) printf(gettext("NFS: Cannot share more than one file "
-			    "system with 'public' property\n"));
-	    err = SA_NOT_ALLOWED;
-	    goto out;
-	}
-
-	if (sp == NULL) {
-		/* failed to alloc memory */
-	    (void) printf("NFS: no memory for security\n");
-	    err = SA_NO_MEMORY;
-	} else {
-	    int i;
-	    export.ex_secinfo = sp;
-	    /* get default secinfo */
-	    export.ex_seccnt = num_secinfo;
-		/*
-		 * since we must have one security option defined, we
-		 * init to the default and then override as we find
-		 * defined security options. This handles the case
-		 * where we have no defined options but we need to set
-		 * up one.
-		 */
-	    sp[0].s_window = DEF_WIN;
-	    sp[0].s_rootnames = NULL;
-	    /* setup a default in case no properties defined */
-	    if (nfs_getseconfig_default(&sp[0].s_secinfo)) {
-		(void) printf(gettext("NFS: nfs_getseconfig_default: failed to "
-				"get default security mode\n"));
-		err = SA_CONFIG_ERR;
-	    }
-	    if (secoptlist != NULL) {
-		for (i = 0, prop = sa_get_property(secoptlist, NULL);
-		    prop != NULL && i < num_secinfo;
-		    prop = sa_get_next_property(prop), i++) {
-		    char *sectype;
-
-		    sectype = sa_get_property_attr(prop, "type");
-		    /* if sectype is NULL, we can't do anything so skip */
-		    if (sectype == NULL)
-			continue;
-		    sec = (sa_security_t)sa_get_derived_security(share,
-								sectype,
-								"nfs", 1);
-		    sp[i].s_window = DEF_WIN;
-		    sp[i].s_rootcnt = 0;
-		    sp[i].s_rootnames = NULL;
-
-		    (void) fill_security_from_secopts(&sp[i], sec);
-		    if (sec != NULL)
-			sa_free_derived_security(sec);
-		    if (sectype != NULL)
-			sa_free_attr_string(sectype);
-		}
-	    }
-		/*
-		 * when we get here, we can do the exportfs system call and
-		 * initiate thinsg. We probably want to enable the nfs.server
-		 * service first if it isn't running within SMF.
-		 */
-		/* check nfs.server status and start if needed */
-
-		/* now add the share to the internal tables */
-	    printarg(path, &export);
-		/*
-		 * call the exportfs system call which is implemented
-		 * via the nfssys() call as the EXPORTFS subfunction.
-		 */
-	    if ((err = exportfs(path, &export)) < 0) {
-		err = SA_SYSTEM_ERR;
-		switch (errno) {
-		case EREMOTE:
-		    (void) printf(gettext("NFS: Cannot share remote file"
-						"system: %s\n"),
-					path);
-		    break;
-		case EPERM:
-		    if (getzoneid() != GLOBAL_ZONEID) {
-			(void) printf(gettext("NFS: Cannot share file systems "
-					"in non-global zones: %s\n"), path);
-			err = SA_NOT_SUPPORTED;
-			break;
-		    }
-		    err = SA_NO_PERMISSION;
-		    /* FALLTHROUGH */
-		default:
-		    break;
-		}
-	    } else {
-		/* update sharetab with an add/modify */
-		(void) sa_update_sharetab(share, "nfs");
-	    }
-	}
-
-	if (err == SA_OK) {
-		/*
-		 * enable services as needed. This should probably be
-		 * done elsewhere in order to minimize the calls to
-		 * check services.
-		 */
-		/*
-		 * check to see if logging and other services need to
-		 * be triggered, but only if there wasn't an
-		 * error. This is probably where sharetab should be
-		 * updated with the NFS specific entry.
-		 */
-	    if (export.ex_flags & EX_LOG) {
-		/* enable logging */
-		if (nfslogtab_add(path, export.ex_log_buffer,
-		    export.ex_tag) != 0) {
-		    (void) fprintf(stderr,
-				gettext("Could not enable logging for %s\n"),
-				path);
-		}
-		_check_services(service_list_logging);
-	    } else {
-		/*
-		 * don't have logging so remove it from file. It might
-		 * not be thre, but that doesn't matter.
-		 */
-		(void) nfslogtab_deactivate(path);
-		_check_services(service_list_default);
-	    }
-	}
-
-out:
-	if (path != NULL)
-	    free(path);
-
-	cleanup_export(&export);
-	if (opt != NULL)
-	    sa_free_derived_optionset(opt);
-	if (secoptlist != NULL)
-	    (void) sa_destroy_optionset(secoptlist);
-	return (err);
-}
-
-/*
- * nfs_disable_share(share)
- *
- * Unshare the specified share.  How much error checking should be
- * done? We only do basic errors for now.
- */
-static int
-nfs_disable_share(char *share)
-{
-	int err;
-	int ret = SA_OK;
-
-	if (share != NULL) {
-	    err = exportfs(share, NULL);
-	    if (err < 0) {
-		/* TBD: only an error in some cases - need better analysis */
-		switch (errno) {
-		case EPERM:
-		case EACCES:
-		    ret = SA_NO_PERMISSION;
-		    if (getzoneid() != GLOBAL_ZONEID) {
-			ret = SA_NOT_SUPPORTED;
-		    }
-		    break;
-		case EINVAL:
-		case ENOENT:
-		    ret = SA_NO_SUCH_PATH;
-		    break;
-		default:
-		    ret = SA_SYSTEM_ERR;
-		    break;
-		}
-	    }
-	    if (ret == SA_OK || ret == SA_NO_SUCH_PATH) {
-		(void) sa_delete_sharetab(share, "nfs");
-		/* just in case it was logged */
-		(void) nfslogtab_deactivate(share);
-	    }
-	}
-	return (ret);
-}
-
-/*
- * check ro vs rw values.  Over time this may get beefed up.
- * for now it just does simple checks.
- */
-
-static int
-check_rorw(char *v1, char *v2)
-{
-	int ret = SA_OK;
-	if (strcmp(v1, v2) == 0)
-	    ret = SA_VALUE_CONFLICT;
-	return (ret);
-}
-
-/*
- * nfs_validate_property(property, parent)
- *
- * Check that the property has a legitimate value for its type.
- */
-
-static int
-nfs_validate_property(sa_property_t property, sa_optionset_t parent)
-{
-	int ret = SA_OK;
-	char *propname;
-	char *other;
-	int optindex;
-	nfsl_config_t *configlist;
-	sa_group_t parent_group;
-	char *value;
-
-	propname = sa_get_property_attr(property, "type");
-
-	if ((optindex = findopt(propname)) < 0)
-	    ret = SA_NO_SUCH_PROP;
-
-	/* need to validate value range here as well */
-
-	if (ret == SA_OK) {
-	    parent_group = sa_get_parent_group((sa_share_t)parent);
-	    if (optdefs[optindex].share && !sa_is_share(parent_group)) {
-		ret = SA_PROP_SHARE_ONLY;
-	    }
-	}
-	if (ret == SA_OK) {
-	    value = sa_get_property_attr(property, "value");
-	    if (value != NULL) {
-		/* first basic type checking */
-		switch (optdefs[optindex].type) {
-		case OPT_TYPE_NUMBER:
-		    /* check that the value is all digits */
-		    if (!is_a_number(value))
-			ret = SA_BAD_VALUE;
-		    break;
-		case OPT_TYPE_BOOLEAN:
-		    if (strlen(value) == 0 ||
-			strcasecmp(value, "true") == 0 ||
-			strcmp(value, "1") == 0 ||
-			strcasecmp(value, "false") == 0 ||
-			strcmp(value, "0") == 0) {
-			ret = SA_OK;
-		    } else {
-			ret = SA_BAD_VALUE;
-		    }
-		    break;
-		case OPT_TYPE_USER:
-		    if (!is_a_number(value)) {
-			struct passwd *pw;
-			/* in this case it would have to be a user name */
-			pw = getpwnam(value);
-			if (pw == NULL)
-			    ret = SA_BAD_VALUE;
-			endpwent();
-		    } else {
-			uint64_t intval;
-			intval = strtoull(value, NULL, 0);
-			if (intval > UID_MAX && intval != ~0)
-			    ret = SA_BAD_VALUE;
-		    }
-		    break;
-		case OPT_TYPE_FILE:
-		    if (strcmp(value, "..") == 0 ||
-			strchr(value, '/') != NULL) {
-			ret = SA_BAD_VALUE;
-		    }
-		    break;
-		case OPT_TYPE_ACCLIST:
-			/*
-			 * access list handling. Should eventually
-			 * validate that all the values make sense.
-			 * Also, ro and rw may have cross value
-			 * conflicts.
-			 */
-		    if (strcmp(propname, SHOPT_RO) == 0)
-			other = SHOPT_RW;
-		    else if (strcmp(propname, SHOPT_RW) == 0)
-			other = SHOPT_RO;
-		    else
-			other = NULL;
-		    if (other != NULL && parent != NULL) {
-			/* compare rw(ro) with ro(rw) */
-			sa_property_t oprop;
-			oprop = sa_get_property(parent, other);
-			if (oprop != NULL) {
-			    /* only potential confusion if other exists */
-			    char *ovalue;
-			    ovalue = sa_get_property_attr(oprop, "value");
-			    if (ovalue != NULL) {
-				ret = check_rorw(value, ovalue);
-				sa_free_attr_string(ovalue);
-			    }
-			}
-		    }
-		    break;
-		case OPT_TYPE_LOGTAG:
-		    if (nfsl_getconfig_list(&configlist) == 0) {
-			int error;
-			if (value == NULL || strlen(value) == 0) {
-			    if (value != NULL)
-				sa_free_attr_string(value);
-			    value = strdup("global");
-			}
-			if (nfsl_findconfig(configlist, value, &error) == NULL)
-			    ret = SA_BAD_VALUE;
-			nfsl_freeconfig_list(&configlist);
-		    } else {
-			ret = SA_CONFIG_ERR;
-		    }
-		    break;
-		case OPT_TYPE_STRING:
-		    /* whatever is here should be ok */
-		    break;
-		case OPT_TYPE_SECURITY:
-			/*
-			 * The "sec" property isn't used in the
-			 * non-legacy parts of sharemgr. We need to
-			 * reject it here. For legacy, it is pulled
-			 * out well before we get here.
-			 */
-		    ret = SA_NO_SUCH_PROP;
-		    break;
-		default:
-		    break;
-		}
-		sa_free_attr_string(value);
-		if (ret == SA_OK && optdefs[optindex].check != NULL) {
-		    /* do the property specific check */
-		    ret = optdefs[optindex].check(property);
-		}
-	    }
-	}
-
-	if (propname != NULL)
-	    sa_free_attr_string(propname);
-	return (ret);
-}
-
-/*
- * Protocol management functions
- *
- * Properties defined in the default files are defined in
- * proto_option_defs for parsing and validation. If "other" and
- * "compare" are set, then the value for this property should be
- * compared against the property specified in "other" using the
- * "compare" check (either <= or >=) in order to ensure that the
- * values are in the correct range.  E.g. setting server_versmin
- * higher than server_versmax should not be allowed.
- */
-
-struct proto_option_defs {
-	char *tag;
-	char *name;	/* display name -- remove protocol identifier */
-	int index;
-	int type;
-	union {
-	    int intval;
-	    char *string;
-	} defvalue;
-	uint32_t svcs;
-	int32_t minval;
-	int32_t maxval;
-	char *file;
-	char *other;
-	int compare;
-#define	OPT_CMP_GE	0
-#define	OPT_CMP_LE	1
-	int (*check)(char *);
-} proto_options[] = {
-#define	PROTO_OPT_NFSD_SERVERS			0
-	{"nfsd_servers",
-	    "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 16, SVC_NFSD,
-	    1, INT32_MAX, NFSADMIN},
-#define	PROTO_OPT_LOCKD_LISTEN_BACKLOG		1
-	{"lockd_listen_backlog",
-	    "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG,
-	    OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX, NFSADMIN},
-#define	PROTO_OPT_LOCKD_SERVERS			2
-	{"lockd_servers",
-	    "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 20,
-	    SVC_LOCKD, 1, INT32_MAX, NFSADMIN},
-#define	PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT	3
-	{"lockd_retransmit_timeout",
-	    "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT,
-	    OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX, NFSADMIN},
-#define	PROTO_OPT_GRACE_PERIOD			4
-	{"grace_period",
-	    "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90,
-	    SVC_LOCKD, 0, INT32_MAX, NFSADMIN},
-#define	PROTO_OPT_NFS_SERVER_VERSMIN		5
-	{"nfs_server_versmin",
-	    "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER,
-	    (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
-	    NFS_VERSMAX, NFSADMIN, "server_versmax", OPT_CMP_LE},
-#define	PROTO_OPT_NFS_SERVER_VERSMAX		6
-	{"nfs_server_versmax",
-	    "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER,
-	    (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
-	    NFS_VERSMAX, NFSADMIN, "server_versmin", OPT_CMP_GE},
-#define	PROTO_OPT_NFS_CLIENT_VERSMIN		7
-	{"nfs_client_versmin",
-	    "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER,
-	    (int)NFS_VERSMIN_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX,
-	    NFSADMIN, "client_versmax", OPT_CMP_LE},
-#define	PROTO_OPT_NFS_CLIENT_VERSMAX		8
-	{"nfs_client_versmax",
-	    "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER,
-	    (int)NFS_VERSMAX_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX,
-	    NFSADMIN, "client_versmin", OPT_CMP_GE},
-#define	PROTO_OPT_NFS_SERVER_DELEGATION		9
-	{"nfs_server_delegation",
-	    "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION,
-	    OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0,
-	    NFSADMIN},
-#define	PROTO_OPT_NFSMAPID_DOMAIN		10
-	{"nfsmapid_domain",
-	    "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN,
-	    NULL, SVC_NFSMAPID, 0, 0, NFSADMIN},
-#define	PROTO_OPT_NFSD_MAX_CONNECTIONS		11
-	{"nfsd_max_connections",
-	    "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS,
-	    OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX, NFSADMIN},
-#define	PROTO_OPT_NFSD_PROTOCOL			12
-	{"nfsd_protocol",
-	    "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0,
-	    SVC_NFSD, 0, 0, NFSADMIN},
-#define	PROTO_OPT_NFSD_LISTEN_BACKLOG		13
-	{"nfsd_listen_backlog",
-	    "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG,
-	    OPT_TYPE_NUMBER, 0,
-	    SVC_LOCKD, 0, INT32_MAX, NFSADMIN},
-	{NULL}
-};
-
-/*
- * the protoset holds the defined options so we don't have to read
- * them multiple times
- */
-sa_protocol_properties_t protoset;
-
-static int
-findprotoopt(char *name, int whichname)
-{
-	int i;
-	for (i = 0; proto_options[i].tag != NULL; i++) {
-	    if (whichname == 1) {
-		if (strcasecmp(proto_options[i].name, name) == 0)
-			return (i);
-	    } else {
-		if (strcasecmp(proto_options[i].tag, name) == 0)
-			return (i);
-	    }
-	}
-	return (-1);
-}
-
-/*
- * fixcaselower(str)
- *
- * convert a string to lower case (inplace).
- */
-
-static void
-fixcaselower(char *str)
-{
-	while (*str) {
-	    *str = tolower(*str);
-	    str++;
-	}
-}
-
-/*
- * fixcaseupper(str)
- *
- * convert a string to upper case (inplace).
- */
-
-static void
-fixcaseupper(char *str)
-{
-	while (*str) {
-	    *str = toupper(*str);
-	    str++;
-	}
-}
-
-/*
- * initprotofromdefault()
- *
- * read the default file(s) and add the defined values to the
- * protoset.  Note that default values are known from the built in
- * table in case the file doesn't have a definition.
- */
-
-static int
-initprotofromdefault()
-{
-	FILE *nfs;
-	char buff[BUFSIZ];
-	char *name;
-	char *value;
-	sa_property_t prop;
-	int index;
-
-	protoset = sa_create_protocol_properties("nfs");
-
-	if (protoset != NULL) {
-	    nfs = fopen(NFSADMIN, "r");
-	    if (nfs != NULL) {
-		while (fgets(buff, sizeof (buff), nfs) != NULL) {
-		    switch (buff[0]) {
-		    case '\n':
-		    case '#':
-			/* skip */
-			break;
-		    default:
-			name = buff;
-			buff[strlen(buff) - 1] = '\0';
-			value = strchr(name, '=');
-			if (value != NULL) {
-			    *value++ = '\0';
-			    if ((index = findprotoopt(name, 0)) >= 0) {
-				fixcaselower(name);
-				prop = sa_create_property(
-					proto_options[index].name,
-					value);
-				(void) sa_add_protocol_property(protoset, prop);
-			    }
-			}
-		    }
-		}
-		if (nfs != NULL)
-		    (void) fclose(nfs);
-	    }
-	}
-	if (protoset == NULL)
-	    return (SA_NO_MEMORY);
-	return (SA_OK);
-}
-
-/*
- * add_default()
- *
- * Add the default values for any property not defined in the parsing
- * of the default files. Values are set according to their defined
- * types.
- */
-
-static void
-add_defaults()
-{
-	int i;
-	char number[MAXDIGITS];
-
-	for (i = 0; proto_options[i].tag != NULL; i++) {
-	    sa_property_t prop;
-	    prop = sa_get_protocol_property(protoset, proto_options[i].name);
-	    if (prop == NULL) {
-		/* add the default value */
-		switch (proto_options[i].type) {
-		case OPT_TYPE_NUMBER:
-		    (void) snprintf(number, sizeof (number), "%d",
-				proto_options[i].defvalue.intval);
-		    prop = sa_create_property(proto_options[i].name, number);
-		    break;
-
-		case OPT_TYPE_BOOLEAN:
-		    prop = sa_create_property(proto_options[i].name,
-					proto_options[i].defvalue.intval ?
-					"true" : "false");
-		    break;
-
-		case OPT_TYPE_ONOFF:
-		    prop = sa_create_property(proto_options[i].name,
-					proto_options[i].defvalue.intval ?
-					"on" : "off");
-		    break;
-
-		default:
-		    /* treat as strings of zero length */
-		    prop = sa_create_property(proto_options[i].name, "");
-		    break;
-		}
-		if (prop != NULL)
-		    (void) sa_add_protocol_property(protoset, prop);
-	    }
-	}
-}
-
-static void
-free_protoprops()
-{
-	xmlFreeNode(protoset);
-}
-
-/*
- * nfs_init()
- *
- * Initialize the NFS plugin.
- */
-
-static int
-nfs_init()
-{
-	int ret = SA_OK;
-
-	if (sa_plugin_ops.sa_init != nfs_init)
-	    (void) printf(gettext("NFS plugin not properly initialized\n"));
-
-	ret = initprotofromdefault();
-	add_defaults();
-
-	return (ret);
-}
-
-/*
- * nfs_fini()
- *
- * uninitialize the NFS plugin. Want to avoid memory leaks.
- */
-
-static void
-nfs_fini()
-{
-	free_protoprops();
-}
-
-/*
- * nfs_get_proto_set()
- *
- * Return an optionset with all the protocol specific properties in
- * it.
- */
-
-static sa_protocol_properties_t
-nfs_get_proto_set()
-{
-	return (protoset);
-}
-
-struct deffile {
-	struct deffile *next;
-	char *line;
-};
-
-/*
- * read_default_file(fname)
- *
- * Read the specified default file. We return a list of entries. This
- * get used for adding or removing values.
- */
-
-static struct deffile *
-read_default_file(char *fname)
-{
-	FILE *file;
-	struct deffile *defs = NULL;
-	struct deffile *newdef;
-	struct deffile *prevdef = NULL;
-	char buff[BUFSIZ * 2];
-
-	file = fopen(fname, "r");
-	if (file != NULL) {
-	    while (fgets(buff, sizeof (buff), file) != NULL) {
-		newdef = (struct deffile *)calloc(1, sizeof (struct deffile));
-		if (newdef != NULL) {
-		    newdef->line = strdup(buff);
-		    if (defs == NULL) {
-			prevdef = defs = newdef;
-		    } else {
-			prevdef->next = newdef;
-			prevdef = newdef;
-		    }
-		}
-	    }
-	}
-	(void) fclose(file);
-	return (defs);
-}
-
-static void
-free_default_file(struct deffile *defs)
-{
-	struct deffile *curdefs = NULL;
-
-	while (defs != NULL) {
-	    curdefs = defs;
-	    defs = defs->next;
-	    if (curdefs->line != NULL)
-		free(curdefs->line);
-	    free(curdefs);
-	}
-}
-
-/*
- * write_default_file(fname, defs)
- *
- * Write the default file back.
- */
-
-static int
-write_default_file(char *fname, struct deffile *defs)
-{
-	FILE *file;
-	int ret = SA_OK;
-	sigset_t old, new;
-
-	file = fopen(fname, "w+");
-	if (file != NULL) {
-	    (void) sigprocmask(SIG_BLOCK, NULL, &new);
-	    (void) sigaddset(&new, SIGHUP);
-	    (void) sigaddset(&new, SIGINT);
-	    (void) sigaddset(&new, SIGQUIT);
-	    (void) sigaddset(&new, SIGTSTP);
-	    (void) sigprocmask(SIG_SETMASK, &new, &old);
-	    while (defs != NULL) {
-		(void) fputs(defs->line, file);
-		defs = defs->next;
-	    }
-	    (void) fsync(fileno(file));
-	    (void) sigprocmask(SIG_SETMASK, &old, NULL);
-	    (void) fclose(file);
-	} else {
-	    switch (errno) {
-	    case EPERM:
-	    case EACCES:
-		ret = SA_NO_PERMISSION;
-		break;
-	    default:
-		ret = SA_SYSTEM_ERR;
-	    }
-	}
-	return (ret);
-}
-
-
-/*
- * set_default_file_value(tag, value)
- *
- * Set the default file value for tag to value. Then rewrite the file.
- * tag and value are always set.  The caller must ensure this.
- */
-
-#define	MAX_STRING_LENGTH	256
-static int
-set_default_file_value(char *tag, char *value)
-{
-	int ret = SA_OK;
-	struct deffile *root;
-	struct deffile *defs;
-	struct deffile *prev;
-	char string[MAX_STRING_LENGTH];
-	int len;
-	int update = 0;
-
-	(void) snprintf(string, MAX_STRING_LENGTH, "%s=", tag);
-	len = strlen(string);
-
-	root = defs = read_default_file(NFSADMIN);
-	if (root == NULL) {
-	    if (errno == EPERM || errno == EACCES)
-		ret = SA_NO_PERMISSION;
-	    else
-		ret = SA_SYSTEM_ERR;
-	} else {
-	    while (defs != NULL) {
-		if (defs->line != NULL &&
-		    strncasecmp(defs->line, string, len) == 0) {
-		    /* replace with the new value */
-		    free(defs->line);
-		    fixcaseupper(tag);
-		    (void) snprintf(string, sizeof (string), "%s=%s\n",
-					tag, value);
-		    string[MAX_STRING_LENGTH - 1] = '\0';
-		    defs->line = strdup(string);
-		    update = 1;
-		    break;
-		}
-		defs = defs->next;
-	    }
-	    if (!update) {
-		defs = root;
-		/* didn't find, so see if it is a comment */
-		(void) snprintf(string, MAX_STRING_LENGTH, "#%s=", tag);
-		len = strlen(string);
-		while (defs != NULL) {
-		    if (strncasecmp(defs->line, string, len) == 0) {
-			/* replace with the new value */
-			free(defs->line);
-			fixcaseupper(tag);
-			(void) snprintf(string, sizeof (string),
-				    "%s=%s\n", tag, value);
-			string[MAX_STRING_LENGTH - 1] = '\0';
-			defs->line = strdup(string);
-			update = 1;
-			break;
-		    }
-		    defs = defs->next;
-		}
-	    }
-	    if (!update) {
-		fixcaseupper(tag);
-		(void) snprintf(string, sizeof (string), "%s=%s\n",
-					tag, value);
-		prev = root;
-		while (prev->next != NULL)
-		    prev = prev->next;
-		defs = malloc(sizeof (struct deffile));
-		prev->next = defs;
-		if (defs != NULL) {
-		    defs->next = NULL;
-		    defs->line = strdup(string);
-		}
-	    }
-	    if (update) {
-		ret = write_default_file(NFSADMIN, root);
-	    }
-	    free_default_file(root);
-	}
-	return (ret);
-}
-
-/*
- * service_in_state(service, chkstate)
- *
- * Want to know if the specified service is in the desired state
- * (chkstate) or not. Return true (1) if it is and false (0) if it
- * isn't.
- */
-static int
-service_in_state(char *service, const char *chkstate)
-{
-	char *state;
-	int ret = B_FALSE;
-
-	state = smf_get_state(service);
-	if (state != NULL) {
-	    /* got the state so get the equality for the return value */
-	    ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
-	    free(state);
-	}
-	return (ret);
-}
-
-/*
- * restart_service(svcs)
- *
- * Walk through the bit mask of services that need to be restarted in
- * order to use the new property values. Some properties affect
- * multiple daemons. Should only restart a service if it is currently
- * enabled (online).
- */
-
-static void
-restart_service(uint32_t svcs)
-{
-	uint32_t mask;
-	int ret;
-	char *service;
-
-	for (mask = 1; svcs != 0; mask <<= 1) {
-	    switch (svcs & mask) {
-	    case SVC_LOCKD:
-		service = LOCKD;
-		break;
-	    case SVC_STATD:
-		service = STATD;
-		break;
-	    case SVC_NFSD:
-		service = NFSD;
-		break;
-	    case SVC_MOUNTD:
-		service = MOUNTD;
-		break;
-	    case SVC_NFS4CBD:
-		service = NFS4CBD;
-		break;
-	    case SVC_NFSMAPID:
-		service = NFSMAPID;
-		break;
-	    case SVC_RQUOTAD:
-		service = RQUOTAD;
-		break;
-	    case SVC_NFSLOGD:
-		service = NFSLOGD;
-		break;
-	    default:
-		continue;
-	    }
-
-		/*
-		 * Only attempt to restart the service if it is
-		 * currently running. In the future, it may be
-		 * desirable to use smf_refresh_instance if the NFS
-		 * services ever implement the refresh method.
-		 */
-	    if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
-		ret = smf_restart_instance(service);
-		/*
-		 * There are only a few SMF errors at this point, but
-		 * it is also possible that a bad value may have put
-		 * the service into maintenance if there wasn't an
-		 * SMF level error.
-		 */
-		if (ret != 0) {
-		    (void) fprintf(stderr,
-				gettext("%s failed to restart: %s\n"),
-				scf_strerror(scf_error()));
-		} else {
-			/*
-			 * Check whether it has gone to "maintenance"
-			 * mode or not. Maintenance implies something
-			 * went wrong.
-			 */
-		    if (service_in_state(service, SCF_STATE_STRING_MAINT)) {
-			(void) fprintf(stderr,
-					gettext("%s failed to restart\n"),
-					service);
-		    }
-		}
-	    }
-	    svcs &= ~mask;
-	}
-}
-
-/*
- * nfs_minmax_check(name, value)
- *
- * Verify that the value for the property specified by index is valid
- * relative to the opposite value in the case of a min/max variable.
- * Currently, server_minvers/server_maxvers and
- * client_minvers/client_maxvers are the only ones to check.
- */
-
-static int
-nfs_minmax_check(int index, int value)
-{
-	int val;
-	char *pval;
-	sa_property_t prop;
-	sa_optionset_t opts;
-	int ret = B_TRUE;
-
-	if (proto_options[index].other != NULL) {
-	    /* have a property to compare against */
-	    opts = nfs_get_proto_set();
-	    prop = sa_get_property(opts, proto_options[index].other);
-		/*
-		 * If we don't find the property, assume default
-		 * values which will work since the max will be at the
-		 * max and the min at the min.
-		 */
-	    if (prop != NULL) {
-		pval = sa_get_property_attr(prop, "value");
-		if (pval != NULL) {
-		    val = strtoul(pval, NULL, 0);
-		    if (proto_options[index].compare == OPT_CMP_LE) {
-			ret = value <= val ? B_TRUE : B_FALSE;
-		    } else if (proto_options[index].compare == OPT_CMP_GE) {
-			ret = value >= val ? B_TRUE : B_FALSE;
-		    }
-		}
-	    }
-	}
-	return (ret);
-}
-
-/*
- * nfs_validate_proto_prop(index, name, value)
- *
- * Verify that the property specifed by name can take the new
- * value. This is a sanity check to prevent bad values getting into
- * the default files. All values need to be checked against what is
- * allowed by their defined type. If a type isn't explicitly defined
- * here, it is treated as a string.
- *
- * Note that OPT_TYPE_NUMBER will additionally check that the value is
- * within the range specified and potentially against another property
- * value as well as specified in the proto_options members other and
- * compare.
- */
-
-static int
-nfs_validate_proto_prop(int index, char *name, char *value)
-{
-	int ret = SA_OK;
-	char *cp;
-#ifdef lint
-	name = name;
-#endif
-
-	switch (proto_options[index].type) {
-	case OPT_TYPE_NUMBER:
-	    if (!is_a_number(value))
-		ret = SA_BAD_VALUE;
-	    else {
-		int val;
-		val = strtoul(value, NULL, 0);
-		if (val < proto_options[index].minval ||
-		    val > proto_options[index].maxval)
-		    ret = SA_BAD_VALUE;
-		/*
-		 * For server_versmin/server_versmax and
-		 * client_versmin/client_versmax, the value of the
-		 * min(max) should be checked to be correct relative
-		 * to the current max(min).
-		 */
-		if (!nfs_minmax_check(index, val)) {
-		    ret = SA_BAD_VALUE;
-		}
-	    }
-	    break;
-
-	case OPT_TYPE_DOMAIN:
-		/*
-		 * needs to be a qualified domain so will have at
-		 * least one period and other characters on either
-		 * side of it.  A zero length string is also allowed
-		 * and is the way to turn off the override.
-		 */
-	    if (strlen(value) == 0)
-		break;
-	    cp = strchr(value, '.');
-	    if (cp == NULL || cp == value || strchr(value, '@') != NULL)
-		ret = SA_BAD_VALUE;
-	    break;
-
-	case OPT_TYPE_BOOLEAN:
-	    if (strlen(value) == 0 ||
-		strcasecmp(value, "true") == 0 ||
-		strcmp(value, "1") == 0 ||
-		strcasecmp(value, "false") == 0 ||
-		strcmp(value, "0") == 0) {
-		ret = SA_OK;
-	    } else {
-		ret = SA_BAD_VALUE;
-	    }
-	    break;
-
-	case OPT_TYPE_ONOFF:
-	    if (strcasecmp(value, "on") != 0 &&
-		strcasecmp(value, "off") != 0) {
-		ret = SA_BAD_VALUE;
-	    }
-	    break;
-
-	case OPT_TYPE_PROTOCOL:
-	    if (strcasecmp(value, "all") != 0 &&
-		strcasecmp(value, "tcp") != 0 &&
-		strcasecmp(value, "udp") != 0)
-		ret = SA_BAD_VALUE;
-	    break;
-
-	default:
-	    /* treat as a string */
-	    break;
-	}
-	return (ret);
-}
-
-/*
- * nfs_set_proto_prop(prop)
- *
- * check that prop is valid.
- */
-
-static int
-nfs_set_proto_prop(sa_property_t prop)
-{
-	int ret = SA_OK;
-	char *name;
-	char *value;
-
-	name = sa_get_property_attr(prop, "type");
-	value = sa_get_property_attr(prop, "value");
-	if (name != NULL && value != NULL) {
-	    int index = findprotoopt(name, 1);
-	    if (index >= 0) {
-		/* should test for valid value */
-		ret = nfs_validate_proto_prop(index, name, value);
-		if (ret == SA_OK)
-		    ret = set_default_file_value(proto_options[index].tag,
-							value);
-		if (ret == SA_OK)
-		    restart_service(proto_options[index].svcs);
-	    }
-	}
-	if (name != NULL)
-	    sa_free_attr_string(name);
-	if (value != NULL)
-	    sa_free_attr_string(value);
-	return (ret);
-}
-
-/*
- * nfs_get_status()
- *
- * What is the current status of the nfsd? We use the SMF state here.
- * Caller must free the returned value.
- */
-
-static char *
-nfs_get_status()
-{
-	char *state;
-	state = smf_get_state(NFSD);
-	return (state != NULL ? state : strdup("-"));
-}
-
-/*
- * nfs_space_alias(alias)
- *
- * Lookup the space (security) name. If it is default, convert to the
- * real name.
- */
-
-static char *
-nfs_space_alias(char *space)
-{
-	char *name = space;
-	seconfig_t secconf;
-
-	/*
-	 * Only the space named "default" is special. If it is used,
-	 * the default needs to be looked up and the real name used.
-	 * This is normally "sys" but could be changed.  We always
-	 * change defautl to the real name.
-	 */
-	if (strcmp(space, "default") == 0 &&
-	    nfs_getseconfig_default(&secconf) == 0) {
-	    if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0)
-		name = secconf.sc_name;
-	}
-	return (strdup(name));
-}
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.h	Wed Mar 28 07:55:32 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * basic API declarations for share management
- */
-
-#ifndef _LIBSHARE_NFS_H
-#define	_LIBSHARE_NFS_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/* property names used by NFS */
-#define	SHOPT_RO	"ro"
-#define	SHOPT_RW	"rw"
-
-#define	SHOPT_SEC	"sec"
-#define	SHOPT_SECURE	"secure"
-#define	SHOPT_ROOT	"root"
-#define	SHOPT_ANON	"anon"
-#define	SHOPT_WINDOW	"window"
-#define	SHOPT_NOSUB	"nosub"
-#define	SHOPT_NOSUID	"nosuid"
-#define	SHOPT_ACLOK	"aclok"
-#define	SHOPT_PUBLIC	"public"
-#define	SHOPT_INDEX	"index"
-#define	SHOPT_LOG	"log"
-#define	SHOPT_CKSUM	"cksum"
-
-/*
- * defined options types. These should be in a file rather than
- * compiled in. Until there is a plugin mechanism to add new types,
- * this is sufficient.
- */
-#define	OPT_TYPE_ANY		0
-#define	OPT_TYPE_STRING		1
-#define	OPT_TYPE_BOOLEAN	2
-#define	OPT_TYPE_NUMBER		3
-#define	OPT_TYPE_RANGE		4
-#define	OPT_TYPE_USER		5
-#define	OPT_TYPE_ACCLIST	6
-#define	OPT_TYPE_DEPRECATED	7
-#define	OPT_TYPE_SECURITY	8
-#define	OPT_TYPE_PATH		9
-#define	OPT_TYPE_FILE		10
-#define	OPT_TYPE_LOGTAG		11
-#define	OPT_TYPE_STRINGSET	12
-#define	OPT_TYPE_DOMAIN		13
-#define	OPT_TYPE_ONOFF		14
-#define	OPT_TYPE_PROTOCOL	15
-
-#define	OPT_SHARE_ONLY		1
-
-struct option_defs {
-	char *tag;
-	int index;
-	int type;
-	int share;	/* share only option */
-	int (*check)(char *);
-};
-
-/*
- * service bit mask values
- */
-#define	SVC_LOCKD	0x0001
-#define	SVC_STATD	0x0002
-#define	SVC_NFSD	0x0004
-#define	SVC_MOUNTD	0x0008
-#define	SVC_NFS4CBD	0x0010
-#define	SVC_NFSMAPID	0x0020
-#define	SVC_RQUOTAD	0x0040
-#define	SVC_NFSLOGD	0x0080
-
-/*
- * place holder for future service -- will move to daemon_utils.h when
- * fully implemented.
- */
-#define	NFSLOGD	"svc:/network/nfs/log:default"
-
-/* The NFS export structure flags for read/write modes */
-#define	NFS_RWMODES	(M_RO|M_ROL|M_RW|M_RWL)
-
-/* other values */
-/* max size of 64-bit integer in digits plus a bit extra */
-#define	MAXDIGITS	32
-
-/* external variable */
-extern boolean_t nfsl_errs_to_syslog;
-
-/* imported functions */
-extern int exportfs(char *, struct exportdata *);
-extern void _check_services(char **);
-extern int nfs_getseconfig_default(seconfig_t *);
-extern int nfs_getseconfig_byname(char *, seconfig_t *);
-extern bool_t nfs_get_root_principal(seconfig_t *, char *, caddr_t *);
-extern int nfsl_getconfig_list(nfsl_config_t **);
-extern void nfsl_freeconfig_list(nfsl_config_t **);
-extern nfsl_config_t *nfsl_findconfig(nfsl_config_t *, char *, int *);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif /* _LIBSHARE_NFS_H */
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/sparc/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-
-install: all
--- a/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h	Wed Mar 28 08:50:43 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,6 +32,7 @@
 #ifdef	__cplusplus
 extern "C" {
 #endif
+#include <libshare.h>
 
 /*
  * shareadm internal interfaces
@@ -68,7 +69,7 @@
 typedef struct sa_command {
 	char	*cmdname;
 	int	flags;
-	int	(*cmdfunc)(int, int, char **);
+	int	(*cmdfunc)(sa_handle_t, int, int, char **);
 	int	cmdidx;
 	int	priv;	/* requires RBAC authorizations */
 } sa_command_t;
@@ -107,7 +108,7 @@
 };
 
 /* shareutil entry points */
-    extern int add_opt(struct options **, char *, int);
+extern int add_opt(struct options **, char *, int);
 
 
 #ifdef	__cplusplus
--- a/usr/src/cmd/dfs.cmds/sharemgr/sharemgr_main.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/sharemgr_main.c	Wed Mar 28 08:50:43 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,7 +42,7 @@
 char *protocol = NULL;
 static int help = 0;
 
-static int run_command(char *, int, char **, char *);
+static int run_command(char *, int, char **, char *, sa_handle_t);
 extern sa_command_t *sa_lookup(char *, char *);
 extern void sub_command_help(char *proto);
 
@@ -59,6 +59,7 @@
 	int c;
 	int rval;
 	char *command = NULL;
+	sa_handle_t handle;
 
 	/*
 	 * make sure locale and gettext domain is setup
@@ -109,21 +110,22 @@
 	 */
 
 	optind = 1;
-	sa_init(SA_INIT_SHARE_API);
+	handle = sa_init(SA_INIT_SHARE_API);
 
 	/*
 	 * reset optind again since we will start parsing all over in
 	 * the sub-commands.
 	 */
 	optind = 1;
-	rval = run_command(command, argc, argv, protocol);
+	rval = run_command(command, argc, argv, protocol, handle);
 
-	sa_fini();
+	sa_fini(handle);
 	return (rval);
 }
 
 static int
-run_command(char *command, int argc, char *argv[], char *proto)
+run_command(char *command, int argc, char *argv[], char *proto,
+		sa_handle_t handle)
 {
 	sa_command_t *cmdvec;
 	int ret;
@@ -154,6 +156,6 @@
 	 * based on least priviledge and sub-command so pass this in
 	 * as a flag.
 	 */
-	ret = cmdvec->cmdfunc(cmdvec->priv, argc, argv);
+	ret = cmdvec->cmdfunc(handle, cmdvec->priv, argc, argv);
 	return (ret);
 }
--- a/usr/src/cmd/dfs.cmds/sharemgr/sparc/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/cmd/dfs.cmds/sharemgr/sparc/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -21,10 +21,10 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 include ../Makefile.com
 
-install: all
+install: all $(ROOTUSRSBINPROG32) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/dfs.cmds/sharemgr/sparcv9/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.cmd.64
+
+install: all $(ROOTUSRSBINPROG64)
--- a/usr/src/lib/libshare/Makefile	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -27,9 +27,18 @@
 
 include ../Makefile.lib
 
-HDRS =		libshare.h
+HDRS =		libshare.h libshare_impl.h scfutil.h
 HDRDIR =	common
-SUBDIRS =	$(MACH)
+
+MACHS = $(MACH)
+$(BUILD64)MACHS += $(MACH64)
+
+# Add plugin module directories here. They need to build after the libshare
+# objects are built.
+PLUGINS =	nfs
+$(PLUGINS):	$(MACHS)
+
+SUBDIRS =	$(MACHS) $(PLUGINS)
 
 MSGFILES=	common/libshare.c common/libsharecore.c common/scfutil.c \
 		common/plugin.c common/parser.c common/libshare_zfs.c
--- a/usr/src/lib/libshare/Makefile.com	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/Makefile.com	Wed Mar 28 08:50:43 2007 -0700
@@ -47,8 +47,7 @@
 
 #add nfs/lib directory as part of the include path
 CFLAGS +=	$(CCVERBOSE)
-CPPFLAGS +=	-D_REENTRANT -I$(NFSLIB_DIR) -I/usr/include/libxml2 \
-		-I$(SRCDIR)
+CPPFLAGS +=	-D_REENTRANT -I$(NFSLIB_DIR) -I/usr/include/libxml2
 
 .KEEP_STATE:
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/amd64/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/lib/libshare/common/libshare.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/libshare.c	Wed Mar 28 08:50:43 2007 -0700
@@ -44,6 +44,8 @@
 #include "scfutil.h"
 #include <ctype.h>
 #include <libintl.h>
+#include <thread.h>
+#include <synch.h>
 
 #if _NOT_SMF
 #define	CONFIG_FILE	"/var/tmp/share.cfg"
@@ -58,14 +60,11 @@
  * internal data structures
  */
 
-static xmlNodePtr sa_config_tree;	/* the current config */
-static xmlDocPtr  sa_config_doc = NULL;	/* current config document */
 extern struct sa_proto_plugin *sap_proto_list;
 
 /* current SMF/SVC repository handle */
-static scfutilhandle_t *scf_handle = NULL;
-extern void getlegacyconfig(char *, xmlNodePtr *);
-extern int gettransients(xmlNodePtr *);
+extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
+extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
 extern int sa_valid_property(void *, char *, sa_property_t);
 extern char *sa_fstype(char *);
 extern int sa_is_share(void *);
@@ -73,17 +72,37 @@
 extern int sa_group_is_zfs(sa_group_t);
 extern int sa_path_is_zfs(char *);
 extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
-extern void update_legacy_config(void);
+extern void update_legacy_config(sa_handle_t);
 extern int issubdir(char *, char *);
-extern void sa_zfs_init(void);
-extern void sa_zfs_fini(void);
+extern void sa_zfs_init(sa_handle_impl_t);
+extern void sa_zfs_fini(sa_handle_impl_t);
 extern void sablocksigs(sigset_t *);
 extern void saunblocksigs(sigset_t *);
 
-static int sa_initialized = 0;
+/*
+ * Data structures for finding/managing the document root to access
+ * handle mapping. The list isn't expected to grow very large so a
+ * simple list is acceptable. The purpose is to provide a way to start
+ * with a group or share and find the library handle needed for
+ * various operations.
+ */
+mutex_t sa_global_lock;
+struct doc2handle {
+	struct doc2handle	*next;
+	xmlNodePtr		root;
+	sa_handle_impl_t	handle;
+};
+
+static struct doc2handle *sa_global_handles = NULL;
 
 /* helper functions */
 
+/*
+ * sa_errorstr(err)
+ *
+ * convert an error value to an error string
+ */
+
 char *
 sa_errorstr(int err)
 {
@@ -172,6 +191,102 @@
 }
 
 /*
+ * Document root to active handle mapping functions.  These are only
+ * used internally. A mutex is used to prevent access while the list
+ * is changing. In general, the list will be relatively short - one
+ * item per thread that has called sa_init().
+ */
+
+sa_handle_impl_t
+get_handle_for_root(xmlNodePtr root)
+{
+	struct doc2handle *item;
+
+	(void) mutex_lock(&sa_global_lock);
+	for (item = sa_global_handles; item != NULL; item = item->next) {
+	    if (item->root == root)
+		break;
+	}
+	(void) mutex_unlock(&sa_global_lock);
+	if (item != NULL)
+	    return (item->handle);
+	return (NULL);
+}
+
+static int
+add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle)
+{
+	struct doc2handle *item;
+	int ret = SA_NO_MEMORY;
+
+	item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1);
+	if (item != NULL) {
+	    item->root = root;
+	    item->handle = handle;
+	    (void) mutex_lock(&sa_global_lock);
+	    item->next = sa_global_handles;
+	    sa_global_handles = item;
+	    (void) mutex_unlock(&sa_global_lock);
+	    ret = SA_OK;
+	}
+	return (ret);
+}
+
+/*
+ * remove_handle_for_root(root)
+ *
+ * Walks the list of handles and removes the one for this "root" from
+ * the list. It is up to the caller to free the data.
+ */
+
+static void
+remove_handle_for_root(xmlNodePtr root)
+{
+	struct doc2handle *item, *prev;
+
+	(void) mutex_lock(&sa_global_lock);
+	for (prev = NULL, item = sa_global_handles; item != NULL;
+		item = item->next) {
+	    if (item->root == root) {
+		if (prev == NULL) {
+		    /* first in the list */
+		    sa_global_handles = sa_global_handles->next;
+		} else {
+		    prev->next = item->next;
+		}
+		/* Item is out of the list so free the list structure */
+		free(item);
+		break;
+	    }
+	    prev = item;
+	}
+	(void) mutex_unlock(&sa_global_lock);
+}
+
+/*
+ * sa_find_group_handle(sa_group_t group)
+ *
+ * Find the sa_handle_t for the configuration associated with this
+ * group.
+ */
+sa_handle_t
+sa_find_group_handle(sa_group_t group)
+{
+	xmlNodePtr node = (xmlNodePtr)group;
+	sa_handle_t handle;
+
+	while (node != NULL) {
+	    if (strcmp((char *)(node->name), "sharecfg") == 0) {
+		/* have the root so get the handle */
+		handle = (sa_handle_t)get_handle_for_root(node);
+		return (handle);
+	    }
+	    node = node->parent;
+	}
+	return (NULL);
+}
+
+/*
  * set_legacy_timestamp(root, path, timevalue)
  *
  * add the current timestamp value to the configuration for use in
@@ -184,6 +299,12 @@
 {
 	xmlNodePtr node;
 	xmlChar *lpath = NULL;
+	sa_handle_impl_t handle;
+
+	/* Have to have a handle or else we weren't initialized. */
+	handle = get_handle_for_root(root);
+	if (handle == NULL)
+	    return;
 
 	for (node = root->xmlChildrenNode; node != NULL;
 		node = node->next) {
@@ -210,16 +331,16 @@
 	    xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring);
 	    xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path);
 	    /* now commit to SMF */
-	    ret = sa_get_instance(scf_handle, "default");
+	    ret = sa_get_instance(handle->scfhandle, "default");
 	    if (ret == SA_OK) {
-		ret = sa_start_transaction(scf_handle, "operation");
+		ret = sa_start_transaction(handle->scfhandle, "operation");
 		if (ret == SA_OK) {
-		    ret = sa_set_property(scf_handle, "legacy-timestamp",
+		    ret = sa_set_property(handle->scfhandle, "legacy-timestamp",
 					    tstring);
 		    if (ret == SA_OK) {
-			(void) sa_end_transaction(scf_handle);
+			(void) sa_end_transaction(handle->scfhandle);
 		    } else {
-			sa_abort_transaction(scf_handle);
+			sa_abort_transaction(handle->scfhandle);
 		    }
 		}
 	    }
@@ -314,13 +435,13 @@
  * and those * stored in the repository
  */
 static int
-checksubdir(char *newpath, int strictness)
+checksubdir(sa_handle_t handle, char *newpath, int strictness)
 {
 	sa_group_t group;
 	int issub;
 	char *path = NULL;
 
-	for (issub = 0, group = sa_get_group(NULL);
+	for (issub = 0, group = sa_get_group(handle, NULL);
 		group != NULL && !issub;
 		group = sa_get_next_group(group)) {
 	    if (sa_group_is_zfs(group)) {
@@ -345,7 +466,7 @@
  * share path.
  */
 static int
-validpath(char *path, int strictness)
+validpath(sa_handle_t handle, char *path, int strictness)
 {
 	int error = SA_OK;
 	struct stat st;
@@ -358,7 +479,7 @@
 	if (stat(path, &st) < 0) {
 	    error = SA_NO_SUCH_PATH;
 	} else {
-	    share = sa_find_share(path);
+	    share = sa_find_share(handle, path);
 	    if (share != NULL) {
 		error = SA_DUPLICATE_NAME;
 	    }
@@ -373,14 +494,14 @@
 		 */
 		fstype = sa_fstype(path);
 		if (fstype != NULL && strcmp(fstype, "zfs") == 0) {
-		    if (sa_zfs_is_shared(path))
+		    if (sa_zfs_is_shared(handle, path))
 			error = SA_INVALID_NAME;
 		}
 		if (fstype != NULL)
 		    sa_free_fstype(fstype);
 	    }
 	    if (error == SA_OK) {
-		error = checksubdir(path, strictness);
+		error = checksubdir(handle, path, strictness);
 	    }
 	}
 	return (error);
@@ -531,7 +652,7 @@
  *	read in the current configuration
  */
 
-void
+sa_handle_t
 sa_init(int init_service)
 {
 	struct stat st;
@@ -541,8 +662,12 @@
 	sigset_t old;
 	int updatelegacy = B_FALSE;
 	scf_simple_prop_t *prop;
+	sa_handle_impl_t handle;
+	int err;
 
-	if (!sa_initialized) {
+	handle = calloc(sizeof (struct sa_handle_impl), 1);
+
+	if (handle != NULL) {
 	    /* get protocol specific structures */
 	    (void) proto_plugin_init();
 	    if (init_service & SA_INIT_SHARE_API) {
@@ -550,13 +675,13 @@
 		 * initialize access into libzfs. We use this when
 		 * collecting info about ZFS datasets and shares.
 		 */
-		sa_zfs_init();
+		sa_zfs_init(handle);
 		/*
 		 * since we want to use SMF, initialize an svc handle
 		 * and find out what is there.
 		 */
-		scf_handle = sa_scf_init();
-		if (scf_handle != NULL) {
+		handle->scfhandle = sa_scf_init(handle);
+		if (handle->scfhandle != NULL) {
 			/*
 			 * Need to lock the extraction of the
 			 * configuration if the dfstab file has
@@ -585,7 +710,7 @@
 			 * lock will make any changes before the
 			 * others can read the repository.
 			 */
-			prop = scf_simple_prop_get(scf_handle->handle,
+			prop = scf_simple_prop_get(handle->scfhandle->handle,
 						(const char *)
 						    SA_SVC_FMRI_BASE ":default",
 						"operation",
@@ -610,14 +735,28 @@
 			(void) lockf(lockfd, F_ULOCK, 0);
 			(void) close(lockfd);
 		    }
-		    (void) sa_get_config(scf_handle, &sa_config_tree,
-				    &sa_config_doc);
+		    (void) sa_get_config(handle->scfhandle, &handle->tree,
+				    &handle->doc, handle);
+		    /* need to setup for later searchs when using group/share */
+		    err = add_handle_for_root(handle->tree, handle);
 		    saunblocksigs(&old);
+
+		    if (err != SA_OK) {
+			/*
+			 * If we couldn't add the tree handle to the
+			 * list, then things are going to fail
+			 * badly. Might as well undo everything now
+			 * and fail the sa_init().
+			 */
+			sa_fini(handle);
+			return (NULL);
+		    }
+
 		    if (tval == 0) {
 			/* first time so make sure default is setup */
 			sa_group_t defgrp;
 			sa_optionset_t opt;
-			defgrp = sa_get_group("default");
+			defgrp = sa_get_group(handle, "default");
 			if (defgrp != NULL) {
 			    opt = sa_get_optionset(defgrp, NULL);
 			    if (opt == NULL)
@@ -627,9 +766,10 @@
 		    }
 		    if (updatelegacy == B_TRUE) {
 			sablocksigs(&old);
-			getlegacyconfig(SA_LEGACY_DFSTAB, &sa_config_tree);
+			getlegacyconfig((sa_handle_t)handle,
+					    SA_LEGACY_DFSTAB, &handle->tree);
 			if (stat(SA_LEGACY_DFSTAB, &st) >= 0)
-			    set_legacy_timestamp(sa_config_tree,
+			    set_legacy_timestamp(handle->tree,
 						SA_LEGACY_DFSTAB,
 						TSTAMP(st.st_ctim));
 			saunblocksigs(&old);
@@ -637,32 +777,48 @@
 			(void) lockf(lockfd, F_ULOCK, 0);
 			(void) close(lockfd);
 		    }
-		    legacy |= sa_get_zfs_shares("zfs");
-		    legacy |= gettransients(&sa_config_tree);
+		    legacy |= sa_get_zfs_shares(handle, "zfs");
+		    legacy |= gettransients(handle, &handle->tree);
 		}
 	    }
 	}
+	return ((sa_handle_t)handle);
 }
 
 /*
- * sa_fini()
+ * sa_fini(handle)
  *	Uninitialize the API structures including the configuration
  *	data structures and ZFS related data.
  */
 
 void
-sa_fini()
+sa_fini(sa_handle_t handle)
 {
-	if (sa_initialized) {
-		/* free the config trees */
-		sa_initialized = 0;
-		if (sa_config_doc != NULL)
-			xmlFreeDoc(sa_config_doc);
-		sa_config_tree = NULL;
-		sa_config_doc = NULL;
-		sa_scf_fini(scf_handle);
-		sa_zfs_fini();
-		(void) proto_plugin_init();
+	sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+
+	if (impl_handle != NULL) {
+		/*
+		 * Free the config trees and any other data structures
+		 * used in the handle.
+		 */
+		if (impl_handle->doc != NULL)
+			xmlFreeDoc(impl_handle->doc);
+		sa_scf_fini(impl_handle->scfhandle);
+		sa_zfs_fini(impl_handle);
+
+		/* Remove and free the entry in the global list. */
+		remove_handle_for_root(impl_handle->tree);
+
+		/* Make sure we free the handle */
+		free(impl_handle);
+
+		/*
+		 * If this was the last handle to release, unload the
+		 * plugins that were loaded.
+		 */
+		if (sa_global_handles == NULL)
+		    (void) proto_plugin_fini();
+
 	}
 }
 
@@ -744,27 +900,28 @@
  *	return the first group of the list of groups.
  */
 sa_group_t
-sa_get_group(char *groupname)
+sa_get_group(sa_handle_t handle, char *groupname)
 {
 	xmlNodePtr node = NULL;
 	char *subgroup = NULL;
 	char *group = NULL;
+	sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
 
-	if (sa_config_tree != NULL) {
+	if (impl_handle != NULL && impl_handle->tree != NULL) {
 	    if (groupname != NULL) {
 		group = strdup(groupname);
 		subgroup = strchr(group, '/');
 		if (subgroup != NULL)
 		    *subgroup++ = '\0';
 	    }
-	    node = find_group_by_name(sa_config_tree, (xmlChar *)group);
+	    node = find_group_by_name(impl_handle->tree, (xmlChar *)group);
 	    /* if a subgroup, find it before returning */
 	    if (subgroup != NULL && node != NULL) {
 		node = find_group_by_name(node, (xmlChar *)subgroup);
 	    }
 	}
 	if (node != NULL && (char *)group != NULL)
-	    (void) sa_get_instance(scf_handle, (char *)group);
+	    (void) sa_get_instance(impl_handle->scfhandle, (char *)group);
 	if (group != NULL)
 	    free(group);
 	return ((sa_group_t)(node));
@@ -918,14 +1075,14 @@
  *	resource names comes into being.
  */
 sa_share_t
-sa_find_share(char *sharepath)
+sa_find_share(sa_handle_t handle, char *sharepath)
 {
 	sa_group_t group;
 	sa_group_t zgroup;
 	sa_share_t share = NULL;
 	int done = 0;
 
-	for (group = sa_get_group(NULL); group != NULL && !done;
+	for (group = sa_get_group(handle, NULL); group != NULL && !done;
 		group = sa_get_next_group(group)) {
 	    if (is_zfs_group(group)) {
 		for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
@@ -959,10 +1116,10 @@
 int
 sa_check_path(sa_group_t group, char *path, int strictness)
 {
-#ifdef lint
-	group = group;
-#endif
-	return (validpath(path, strictness));
+	sa_handle_t handle;
+
+	handle = sa_find_group_handle(group);
+	return (validpath(handle, path, strictness));
 }
 
 /*
@@ -998,8 +1155,13 @@
 		if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) {
 		    err = sa_zfs_set_sharenfs(group, sharepath, 1);
 		} else {
-		    err = sa_commit_share(scf_handle, group,
+		    sa_handle_impl_t impl_handle;
+		    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+		    if (impl_handle != NULL)
+			err = sa_commit_share(impl_handle->scfhandle, group,
 						(sa_share_t)node);
+		    else
+			err = SA_SYSTEM_ERR;
 		}
 	    }
 	    if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) {
@@ -1038,6 +1200,7 @@
 	xmlNodePtr node = NULL;
 	sa_share_t dup;
 	int strictness = SA_CHECK_NORMAL;
+	sa_handle_t handle;
 
 	/*
 	 * If the share is to be permanent, use strict checking so a
@@ -1052,7 +1215,9 @@
 	if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT)
 	    strictness = SA_CHECK_STRICT;
 
-	if ((dup = sa_find_share(sharepath)) == NULL &&
+	handle = sa_find_group_handle(group);
+
+	if ((dup = sa_find_share(handle, sharepath)) == NULL &&
 		(*error = sa_check_path(group, sharepath, strictness)) ==
 			SA_OK) {
 	    node = _sa_add_share(group, sharepath, persist, error);
@@ -1163,7 +1328,13 @@
 	    ret = sa_delete_legacy(share);
 	    if (ret == SA_OK) {
 		if (!sa_group_is_zfs(group)) {
-		    ret = sa_delete_share(scf_handle, group, share);
+		    sa_handle_impl_t impl_handle;
+		    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+		    if (impl_handle != NULL)
+			ret = sa_delete_share(impl_handle->scfhandle,
+						group, share);
+		    else
+			ret = SA_SYSTEM_ERR;
 		} else {
 		    char *sharepath = sa_get_share_attr(share, "path");
 		    if (sharepath != NULL) {
@@ -1200,20 +1371,25 @@
 
 	oldgroup = sa_get_parent_group(share);
 	if (oldgroup != group) {
+	    sa_handle_impl_t impl_handle;
 	    xmlUnlinkNode((xmlNodePtr)share);
 	    /* now that the share isn't in its old group, add to the new one */
 	    xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
 	    /* need to deal with SMF */
-	    if (ret == SA_OK) {
+	    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	    if (impl_handle != NULL) {
 		/*
 		 * need to remove from old group first and then add to
 		 * new group. Ideally, we would do the other order but
 		 * need to avoid having the share in two groups at the
 		 * same time.
 		 */
-		ret = sa_delete_share(scf_handle, oldgroup, share);
+		ret = sa_delete_share(impl_handle->scfhandle, oldgroup, share);
+		if (ret == SA_OK)
+		    ret = sa_commit_share(impl_handle->scfhandle, group, share);
+	    } else {
+		ret = SA_SYSTEM_ERR;
 	    }
-	    ret = sa_commit_share(scf_handle, group, share);
 	}
 	return (ret);
 }
@@ -1244,19 +1420,19 @@
 }
 
 /*
- * _sa_create_group(groupname)
+ * _sa_create_group(impl_handle, groupname)
  *
  * Create a group in the document. The caller will need to deal with
  * configuration store and activation.
  */
 
 sa_group_t
-_sa_create_group(char *groupname)
+_sa_create_group(sa_handle_impl_t impl_handle, char *groupname)
 {
 	xmlNodePtr node = NULL;
 
 	if (sa_valid_group_name(groupname)) {
-	    node = xmlNewChild(sa_config_tree, NULL,
+	    node = xmlNewChild(impl_handle->tree, NULL,
 				(xmlChar *)"group", NULL);
 	    if (node != NULL) {
 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname);
@@ -1298,64 +1474,68 @@
  * (via the SMF transaction model).
  */
 sa_group_t
-sa_create_group(char *groupname, int *error)
+sa_create_group(sa_handle_t handle, char *groupname, int *error)
 {
 	xmlNodePtr node = NULL;
 	sa_group_t group;
 	int ret;
 	char rbacstr[256];
+	sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
 
 	ret = SA_OK;
 
-	if (scf_handle == NULL) {
+	if (impl_handle == NULL || impl_handle->scfhandle == NULL) {
 	    ret = SA_SYSTEM_ERR;
 	    goto err;
 	}
 
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group != NULL) {
 	    ret = SA_DUPLICATE_NAME;
 	} else {
 	    if (sa_valid_group_name(groupname)) {
-		node = xmlNewChild(sa_config_tree, NULL,
+		node = xmlNewChild(impl_handle->tree, NULL,
 				    (xmlChar *)"group", NULL);
 		if (node != NULL) {
 		    xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname);
 		    /* default to the group being enabled */
 		    xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled");
-		    ret = sa_create_instance(scf_handle, groupname);
+		    ret = sa_create_instance(impl_handle->scfhandle, groupname);
 		    if (ret == SA_OK) {
-			ret = sa_start_transaction(scf_handle, "operation");
+			ret = sa_start_transaction(impl_handle->scfhandle,
+							"operation");
 		    }
 		    if (ret == SA_OK) {
-			ret = sa_set_property(scf_handle, "state", "enabled");
+			ret = sa_set_property(impl_handle->scfhandle,
+						"state", "enabled");
 			if (ret == SA_OK) {
-			    ret = sa_end_transaction(scf_handle);
+			    ret = sa_end_transaction(impl_handle->scfhandle);
 			} else {
-			    sa_abort_transaction(scf_handle);
+			    sa_abort_transaction(impl_handle->scfhandle);
 			}
 		    }
 		    if (ret == SA_OK) {
 			/* initialize the RBAC strings */
-			ret = sa_start_transaction(scf_handle, "general");
+			ret = sa_start_transaction(impl_handle->scfhandle,
+							"general");
 			if (ret == SA_OK) {
 			    (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s",
 					SA_RBAC_MANAGE, groupname);
-			    ret = sa_set_property(scf_handle,
+			    ret = sa_set_property(impl_handle->scfhandle,
 						    "action_authorization",
 						    rbacstr);
 			}
 			if (ret == SA_OK) {
 			    (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s",
 					SA_RBAC_VALUE, groupname);
-			    ret = sa_set_property(scf_handle,
+			    ret = sa_set_property(impl_handle->scfhandle,
 						    "value_authorization",
 						    rbacstr);
 			}
 			if (ret == SA_OK) {
-			    ret = sa_end_transaction(scf_handle);
+			    ret = sa_end_transaction(impl_handle->scfhandle);
 			} else {
-			    sa_abort_transaction(scf_handle);
+			    sa_abort_transaction(impl_handle->scfhandle);
 			}
 		    }
 		    if (ret != SA_OK) {
@@ -1392,14 +1572,20 @@
 {
 	char *name;
 	int ret = SA_OK;
+	sa_handle_impl_t impl_handle;
 
-	name = sa_get_group_attr(group, "name");
-	if (name != NULL) {
-	    ret = sa_delete_instance(scf_handle, name);
-	    sa_free_attr_string(name);
+	impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	if (impl_handle != NULL) {
+	    name = sa_get_group_attr(group, "name");
+	    if (name != NULL) {
+		ret = sa_delete_instance(impl_handle->scfhandle, name);
+		sa_free_attr_string(name);
+	    }
+	    xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
+	    xmlFreeNode((xmlNodePtr)group);   /* now it is gone */
+	} else {
+	    ret = SA_SYSTEM_ERR;
 	}
-	xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
-	xmlFreeNode((xmlNodePtr)group);   /* now it is gone */
 	return (ret);
 }
 
@@ -1412,14 +1598,14 @@
  */
 
 int
-sa_update_config()
+sa_update_config(sa_handle_t handle)
 {
 	/*
 	 * do legacy files first so we can tell when they change.
 	 * This will go away when we start updating individual records
 	 * rather than the whole file.
 	 */
-	update_legacy_config();
+	update_legacy_config(handle);
 	return (SA_OK);
 }
 
@@ -1490,23 +1676,29 @@
 {
 	int ret;
 	char *groupname;
+	sa_handle_impl_t impl_handle;
 
-	groupname = sa_get_group_attr(group, "name");
-	ret = sa_get_instance(scf_handle, groupname);
-	if (ret == SA_OK) {
-	    set_node_attr((void *)group, tag, value);
-	    ret = sa_start_transaction(scf_handle, "operation");
+	impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	if (impl_handle != NULL) {
+	    groupname = sa_get_group_attr(group, "name");
+	    ret = sa_get_instance(impl_handle->scfhandle, groupname);
 	    if (ret == SA_OK) {
-		ret = sa_set_property(scf_handle, tag, value);
-		if (ret == SA_OK)
-		    (void) sa_end_transaction(scf_handle);
-		else {
-		    sa_abort_transaction(scf_handle);
+		set_node_attr((void *)group, tag, value);
+		ret = sa_start_transaction(impl_handle->scfhandle, "operation");
+		if (ret == SA_OK) {
+		    ret = sa_set_property(impl_handle->scfhandle, tag, value);
+		    if (ret == SA_OK)
+			(void) sa_end_transaction(impl_handle->scfhandle);
+		    else {
+			sa_abort_transaction(impl_handle->scfhandle);
+		    }
 		}
 	    }
+	    if (groupname != NULL)
+		sa_free_attr_string(groupname);
+	} else {
+	    ret = SA_SYSTEM_ERR;
 	}
-	if (groupname != NULL)
-	    sa_free_attr_string(groupname);
 	return (ret);
 }
 
@@ -1609,8 +1801,15 @@
 		char *type;
 		/* we can probably optimize this some */
 		type = sa_get_share_attr(share, "type");
-		if (type == NULL || strcmp(type, "transient") != 0)
-		    ret = sa_commit_share(scf_handle, group, share);
+		if (type == NULL || strcmp(type, "transient") != 0) {
+		    sa_handle_impl_t impl_handle;
+		    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+		    if (impl_handle != NULL)
+			ret = sa_commit_share(impl_handle->scfhandle,
+						group, share);
+		    else
+			ret = SA_SYSTEM_ERR;
+		}
 		if (type != NULL)
 		    sa_free_attr_string(type);
 	    }
@@ -1894,8 +2093,14 @@
 		xmlUnlinkNode(node);
 		xmlFreeNode(node);
 	}
-	if (group != NULL && is_persistent((sa_group_t)share))
-	    ret = sa_commit_share(scf_handle, group, share);
+	if (group != NULL && is_persistent((sa_group_t)share)) {
+	    sa_handle_impl_t impl_handle;
+	    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	    if (impl_handle != NULL)
+		ret = sa_commit_share(impl_handle->scfhandle, group, share);
+	    else
+		ret = SA_SYSTEM_ERR;
+	}
 	return (ret);
 }
 
@@ -1998,10 +2203,17 @@
 					sizeof (oname), id);
 		groupname = sa_get_group_attr(parent, "name");
 		if (groupname != NULL && is_persistent(group)) {
-			(void) sa_get_instance(scf_handle, groupname);
-			sa_free_attr_string(groupname);
-			(void) sa_create_pgroup(scf_handle, oname);
+		    sa_handle_impl_t impl_handle;
+		    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+		    assert(impl_handle != NULL);
+		    if (impl_handle != NULL) {
+			(void) sa_get_instance(impl_handle->scfhandle,
+						groupname);
+			(void) sa_create_pgroup(impl_handle->scfhandle, oname);
+		    }
 		}
+		if (groupname != NULL)
+		    sa_free_attr_string(groupname);
 		if (id != NULL)
 		    sa_free_attr_string(id);
 	    }
@@ -2097,6 +2309,7 @@
 	int zfs = 0;
 	int needsupdate = 0;
 	int ret = SA_OK;
+	sa_handle_impl_t impl_handle;
 
 	group = sa_get_optionset_parent(optionset);
 	if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) {
@@ -2113,10 +2326,15 @@
 	    if (!clear && needsupdate)
 		ret = sa_zfs_update((sa_share_t)group);
 	} else {
-	    if (clear)
-		(void) sa_abort_transaction(scf_handle);
-	    else
-		ret = sa_end_transaction(scf_handle);
+	    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	    if (impl_handle != NULL) {
+		if (clear)
+		    (void) sa_abort_transaction(impl_handle->scfhandle);
+		else
+		    ret = sa_end_transaction(impl_handle->scfhandle);
+	    } else {
+		ret = SA_SYSTEM_ERR;
+	    }
 	}
 	return (ret);
 }
@@ -2145,9 +2363,15 @@
 	    id = sa_get_share_attr((sa_share_t)group, "id");
 	}
 	if (ispersist) {
+	    sa_handle_impl_t impl_handle;
 	    len = sa_optionset_name(optionset, name, sizeof (name), id);
-	    if (len > 0) {
-		ret = sa_delete_pgroup(scf_handle, name);
+	    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	    if (impl_handle != NULL) {
+		if (len > 0) {
+		    ret = sa_delete_pgroup(impl_handle->scfhandle, name);
+		}
+	    } else {
+		ret = SA_SYSTEM_ERR;
 	    }
 	}
 	xmlUnlinkNode((xmlNodePtr)optionset);
@@ -2209,8 +2433,15 @@
 			(void) sa_security_name(security, oname,
 						sizeof (oname), id);
 			if (groupname != NULL && is_persistent(group)) {
-			    (void) sa_get_instance(scf_handle, groupname);
-			    (void) sa_create_pgroup(scf_handle, oname);
+			    sa_handle_impl_t impl_handle;
+			    impl_handle =
+				(sa_handle_impl_t)sa_find_group_handle(group);
+			    if (impl_handle != NULL) {
+				(void) sa_get_instance(impl_handle->scfhandle,
+							groupname);
+				(void) sa_create_pgroup(impl_handle->scfhandle,
+							oname);
+			    }
 			}
 		}
 	}
@@ -2250,7 +2481,13 @@
 	if (ispersist) {
 	    len = sa_security_name(security, name, sizeof (name), id);
 	    if (!iszfs && len > 0) {
-		ret = sa_delete_pgroup(scf_handle, name);
+		sa_handle_impl_t impl_handle;
+		impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+		if (impl_handle != NULL) {
+		    ret = sa_delete_pgroup(impl_handle->scfhandle, name);
+		} else {
+		    ret = SA_SYSTEM_ERR;
+		}
 	    }
 	}
 	xmlUnlinkNode((xmlNodePtr)security);
@@ -2326,6 +2563,8 @@
 	int iszfs = 0;
 	int isshare = 0;
 	sa_group_t parent = NULL;
+	sa_handle_impl_t impl_handle;
+	scfutilhandle_t  *scf_handle;
 
 	if (!is_persistent(group)) {
 		/*
@@ -2334,6 +2573,11 @@
 		 */
 	    return (SA_OK);
 	}
+	impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	if (impl_handle == NULL || impl_handle->scfhandle == NULL) {
+	    return (SA_SYSTEM_ERR);
+	}
+	scf_handle = impl_handle->scfhandle;
 	name = sa_get_property_attr(prop, "type");
 	valstr = sa_get_property_attr(prop, "value");
 	entry = scf_entry_create(scf_handle->handle);
@@ -2350,68 +2594,68 @@
 		iszfs = is_zfs_group(group);
 	    }
 	    if (!iszfs) {
-		if (scf_handle->trans == NULL) {
-		    char oname[256];
-		    char *groupname = NULL;
-		    if (isshare) {
-			if (parent != NULL) {
-			    groupname = sa_get_group_attr(parent, "name");
+		    if (scf_handle->trans == NULL) {
+			char oname[256];
+			char *groupname = NULL;
+			if (isshare) {
+			    if (parent != NULL) {
+				groupname = sa_get_group_attr(parent, "name");
+			    }
+			    id = sa_get_share_attr((sa_share_t)group, "id");
+			} else {
+			    groupname = sa_get_group_attr(group, "name");
 			}
-			id = sa_get_share_attr((sa_share_t)group, "id");
-		    } else {
-			groupname = sa_get_group_attr(group, "name");
-		    }
-		    if (groupname != NULL) {
-			ret = sa_get_instance(scf_handle, groupname);
-			sa_free_attr_string(groupname);
-		    }
-		    if (opttype)
-			(void) sa_optionset_name(optionset, oname,
+			if (groupname != NULL) {
+			    ret = sa_get_instance(scf_handle, groupname);
+			    sa_free_attr_string(groupname);
+			}
+			if (opttype)
+			    (void) sa_optionset_name(optionset, oname,
 							sizeof (oname), id);
-		    else
-			(void) sa_security_name(optionset, oname,
+			else
+			    (void) sa_security_name(optionset, oname,
 							sizeof (oname), id);
-		    ret = sa_start_transaction(scf_handle, oname);
-		}
-		if (ret == SA_OK) {
-		    switch (type) {
-		    case SA_PROP_OP_REMOVE:
-			ret = scf_transaction_property_delete(scf_handle->trans,
-								entry,
-								name);
-			break;
-		    case SA_PROP_OP_ADD:
-		    case SA_PROP_OP_UPDATE:
-			value = scf_value_create(scf_handle->handle);
-			if (value != NULL) {
-			    if (type == SA_PROP_OP_ADD)
-				ret = scf_transaction_property_new(
-							    scf_handle->trans,
-							    entry,
-							    name,
-							    SCF_TYPE_ASTRING);
-			    else
-				ret = scf_transaction_property_change(
-							    scf_handle->trans,
-							    entry,
-							    name,
-							    SCF_TYPE_ASTRING);
-			    if (ret == 0) {
-				ret = scf_value_set_astring(value, valstr);
-				if (ret == 0)
-				    ret = scf_entry_add_value(entry, value);
-				if (ret != 0) {
-				    scf_value_destroy(value);
+			ret = sa_start_transaction(scf_handle, oname);
+		    }
+		    if (ret == SA_OK) {
+			switch (type) {
+			case SA_PROP_OP_REMOVE:
+			    ret = scf_transaction_property_delete(
+							scf_handle->trans,
+							entry, name);
+			    break;
+			case SA_PROP_OP_ADD:
+			case SA_PROP_OP_UPDATE:
+			    value = scf_value_create(scf_handle->handle);
+			    if (value != NULL) {
+				if (type == SA_PROP_OP_ADD)
+				    ret = scf_transaction_property_new(
+							scf_handle->trans,
+							entry,
+							name,
+							SCF_TYPE_ASTRING);
+				else
+				    ret = scf_transaction_property_change(
+							scf_handle->trans,
+							entry,
+							name,
+							SCF_TYPE_ASTRING);
+				if (ret == 0) {
+				    ret = scf_value_set_astring(value, valstr);
+				    if (ret == 0)
+					ret = scf_entry_add_value(entry, value);
+				    if (ret != 0) {
+					scf_value_destroy(value);
+					ret = SA_SYSTEM_ERR;
+				    }
+				} else {
+				    scf_entry_destroy(entry);
 				    ret = SA_SYSTEM_ERR;
 				}
-			    } else {
-				scf_entry_destroy(entry);
-				ret = SA_SYSTEM_ERR;
+				break;
 			    }
-			    break;
 			}
 		    }
-		}
 	    } else {
 		/*
 		 * ZFS update. The calling function would have updated
@@ -2501,35 +2745,44 @@
 
 	    if (!is_zfs_group(group)) {
 		char *id = NULL;
-		if (sa_is_share((sa_group_t)parent)) {
-		    id = sa_get_share_attr((sa_share_t)parent, "id");
-		}
-		if (scf_handle->trans == NULL) {
-		    if (is_nodetype(object, "optionset"))
-			(void) sa_optionset_name((sa_optionset_t)object,
-					    oname, sizeof (oname), id);
-		    else
-			(void) sa_security_name((sa_optionset_t)object,
-					    oname, sizeof (oname), id);
-		    ret = sa_start_transaction(scf_handle, oname);
-		}
+		sa_handle_impl_t impl_handle;
+		scfutilhandle_t  *scf_handle;
+
+		impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+		if (impl_handle == NULL || impl_handle->scfhandle == NULL)
+		    ret = SA_SYSTEM_ERR;
 		if (ret == SA_OK) {
-		    char *name;
-		    char *value;
-		    name = sa_get_property_attr(property, "type");
-		    value = sa_get_property_attr(property, "value");
-		    if (name != NULL && value != NULL) {
-			if (scf_handle->scf_state == SCH_STATE_INIT)
-			    ret = sa_set_property(scf_handle, name, value);
-		    } else
-			ret = SA_CONFIG_ERR;
-		    if (name != NULL)
-			sa_free_attr_string(name);
-		    if (value != NULL)
-			sa_free_attr_string(value);
+		    scf_handle = impl_handle->scfhandle;
+		    if (sa_is_share((sa_group_t)parent)) {
+			id = sa_get_share_attr((sa_share_t)parent, "id");
+		    }
+		    if (scf_handle->trans == NULL) {
+			if (is_nodetype(object, "optionset"))
+			    (void) sa_optionset_name((sa_optionset_t)object,
+					    oname, sizeof (oname), id);
+			else
+			    (void) sa_security_name((sa_optionset_t)object,
+					    oname, sizeof (oname), id);
+			ret = sa_start_transaction(scf_handle, oname);
+		    }
+		    if (ret == SA_OK) {
+			char *name;
+			char *value;
+			name = sa_get_property_attr(property, "type");
+			value = sa_get_property_attr(property, "value");
+			if (name != NULL && value != NULL) {
+			    if (scf_handle->scf_state == SCH_STATE_INIT)
+				ret = sa_set_property(scf_handle, name, value);
+			} else
+			    ret = SA_CONFIG_ERR;
+			if (name != NULL)
+			    sa_free_attr_string(name);
+			if (value != NULL)
+			    sa_free_attr_string(value);
+		    }
+		    if (id != NULL)
+			sa_free_attr_string(id);
 		}
-		if (id != NULL)
-		    sa_free_attr_string(id);
 	    } else {
 		/*
 		 * ZFS is a special case. We do want to allow editing
@@ -2610,31 +2863,6 @@
 }
 
 /*
- *  _sa_get_next_error(node)
- *
- * Get the next (first if node==NULL) error node in the
- * document. "error" nodes are added if there were syntax errors
- * during parsing of the /etc/dfs/dfstab file. They are preserved in
- * comments and recreated in the doc on the next parse.
- */
-
-xmlNodePtr
-_sa_get_next_error(xmlNodePtr node)
-{
-	if (node == NULL) {
-	    for (node = sa_config_tree->xmlChildrenNode;
-		node != NULL; node = node->next)
-		if (xmlStrcmp(node->name, (xmlChar *)"error") == 0)
-		    return (node);
-	} else {
-	    for (node = node->next; node != NULL; node = node->next)
-		if (xmlStrcmp(node->name, (xmlChar *)"error") == 0)
-		    return (node);
-	}
-	return (node);
-}
-
-/*
  * sa_get_protocol_property(propset, prop)
  *
  * Get the specified protocol specific property. These are global to
--- a/usr/src/lib/libshare/common/libshare.h	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/libshare.h	Wed Mar 28 08:50:43 2007 -0700
@@ -118,9 +118,9 @@
 #define	SA_SVC_FMRI_BASE	"svc:/network/shares/group"
 
 /* initialization */
-extern void sa_init(int);
-extern void sa_fini(void);
-extern int sa_update_config(void);
+extern sa_handle_t sa_init(int);
+extern void sa_fini(sa_handle_t);
+extern int sa_update_config(sa_handle_t);
 extern char *sa_errorstr(int);
 
 /* protocol names */
@@ -128,9 +128,9 @@
 extern int sa_valid_protocol(char *);
 
 /* group control (create, remove, etc) */
-extern sa_group_t sa_create_group(char *, int *);
+extern sa_group_t sa_create_group(sa_handle_t, char *, int *);
 extern int sa_remove_group(sa_group_t);
-extern sa_group_t sa_get_group(char *);
+extern sa_group_t sa_get_group(sa_handle_t, char *);
 extern sa_group_t sa_get_next_group(sa_group_t);
 extern char *sa_get_group_attr(sa_group_t, char *);
 extern int sa_set_group_attr(sa_group_t, char *, char *);
@@ -144,7 +144,7 @@
 extern int sa_remove_share(sa_share_t);
 extern sa_share_t sa_get_share(sa_group_t, char *);
 extern sa_share_t sa_get_resource(sa_group_t, char *);
-extern sa_share_t sa_find_share(char *);
+extern sa_share_t sa_find_share(sa_handle_t, char *);
 extern sa_share_t sa_get_next_share(sa_share_t);
 extern char *sa_get_share_attr(sa_share_t, char *);
 extern char *sa_get_share_description(sa_share_t);
@@ -214,8 +214,13 @@
 extern int sa_delete_sharetab(char *, char *);
 
 /* ZFS functions */
-extern int sa_zfs_is_shared(char *);
+extern int sa_zfs_is_shared(sa_handle_t, char *);
 extern int sa_group_is_zfs(sa_group_t);
+
+
+/* SA Handle specific functions */
+extern sa_handle_t sa_find_group_handle(sa_group_t);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/libshare/common/libshare_impl.h	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/libshare_impl.h	Wed Mar 28 08:50:43 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +37,7 @@
 #include <libshare.h>
 #include <libscf.h>
 #include <scfutil.h>
+#include <libzfs.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -114,11 +115,12 @@
 extern int sa_delete_pgroup(scfutilhandle_t *, char *);
 
 /* ZFS functions */
-extern int sa_get_zfs_shares(char *);
+extern int sa_get_zfs_shares(sa_handle_t, char *);
 extern int sa_zfs_update(sa_share_t);
 
 /* plugin specific functions */
 extern int proto_plugin_init();
+extern void proto_plugin_fini();
 extern int sa_proto_set_property(char *, sa_property_t);
 extern int sa_proto_delete_legacy(char *, sa_share_t);
 extern int sa_proto_update_legacy(char *, sa_share_t);
@@ -136,6 +138,17 @@
 	void			*plugin_handle;
 };
 
+/* internal version of sa_handle_t */
+typedef struct sa_handle_impl {
+	uint64_t	flags;
+	scfutilhandle_t	*scfhandle;
+	libzfs_handle_t *zfs_libhandle;
+	zfs_handle_t	**zfs_list;
+	size_t		zfs_list_count;
+	xmlNodePtr	tree;
+	xmlDocPtr	doc;
+} *sa_handle_impl_t;
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/libshare/common/libshare_zfs.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/libshare_zfs.c	Wed Mar 28 08:50:43 2007 -0700
@@ -50,43 +50,42 @@
 	size_t		cb_used;
 } get_all_cbdata_t;
 
-static libzfs_handle_t *zfs_libhandle = NULL;
-static zfs_handle_t **zfs_list = NULL;
-static size_t zfs_list_count = 0;
-
 /*
- * sa_zfs_init()
+ * sa_zfs_init(impl_handle)
  *
- * initialize an access handle into libzfs
+ * Initialize an access handle into libzfs.  The handle needs to stay
+ * around until sa_zfs_fini() in order to maintain the cache of
+ * mounts.
  */
 
 void
-sa_zfs_init()
+sa_zfs_init(sa_handle_impl_t impl_handle)
 {
-	zfs_libhandle = libzfs_init();
-	libzfs_print_on_error(zfs_libhandle, B_TRUE);
+	impl_handle->zfs_libhandle = libzfs_init();
+	libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
 }
 
 /*
- * sa_zfs_fini()
+ * sa_zfs_fini(impl_handle)
  *
  * cleanup data structures and the libzfs handle used for accessing
  * zfs file share info.
  */
 
 void
-sa_zfs_fini()
+sa_zfs_fini(sa_handle_impl_t impl_handle)
 {
-	if (zfs_libhandle != NULL) {
-	    libzfs_fini(zfs_libhandle);
-	    zfs_libhandle = NULL;
-	    if (zfs_list != NULL) {
+	if (impl_handle->zfs_libhandle != NULL) {
+	    libzfs_fini(impl_handle->zfs_libhandle);
+	    impl_handle->zfs_libhandle = NULL;
+	    if (impl_handle->zfs_list != NULL) {
 		/*
 		 * contents of zfs_list were already freed by the call to
 		 * libzfs_fini().
 		 */
-		free(zfs_list);
-		zfs_list = NULL;
+		free(impl_handle->zfs_list);
+		impl_handle->zfs_list = NULL;
+		impl_handle->zfs_list_count = 0;
 	    }
 	}
 }
@@ -149,20 +148,22 @@
  */
 
 static void
-get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
+get_all_filesystems(sa_handle_impl_t impl_handle,
+			zfs_handle_t ***fslist, size_t *count)
 {
 	get_all_cbdata_t cb = { 0 };
 
-	if (zfs_list != NULL) {
-	    *fslist = zfs_list;
-	    *count = zfs_list_count;
+	if (impl_handle->zfs_list != NULL) {
+	    *fslist = impl_handle->zfs_list;
+	    *count = impl_handle->zfs_list_count;
 	    return;
 	}
 
-	(void) zfs_iter_root(zfs_libhandle, get_one_filesystem, &cb);
+	(void) zfs_iter_root(impl_handle->zfs_libhandle,
+				get_one_filesystem, &cb);
 
-	zfs_list = *fslist = cb.cb_handles;
-	zfs_list_count = *count = cb.cb_used;
+	impl_handle->zfs_list = *fslist = cb.cb_handles;
+	impl_handle->zfs_list_count = *count = cb.cb_used;
 }
 
 /*
@@ -189,7 +190,7 @@
 }
 
 /*
- * get_zfs_dataset(path)
+ * get_zfs_dataset(impl_handle, path)
  *
  * get the name of the ZFS dataset the path is equivalent to.  The
  * dataset name is used for get/set of ZFS properties since libzfs
@@ -197,14 +198,14 @@
  */
 
 static char *
-get_zfs_dataset(char *path)
+get_zfs_dataset(sa_handle_impl_t impl_handle, char *path)
 {
 	size_t i, count = 0;
 	char *dataset = NULL;
 	zfs_handle_t **zlist;
 	char mountpoint[ZFS_MAXPROPLEN];
 
-	get_all_filesystems(&zlist, &count);
+	get_all_filesystems(impl_handle, &zlist, &count);
 	qsort(zlist, count, sizeof (void *), mountpoint_compare);
 	for (i = 0; i < count; i++) {
 	    /* must have a mountpoint */
@@ -272,14 +273,14 @@
 }
 
 /*
- * sa_zfs_is_shared(path)
+ * sa_zfs_is_shared(handle, path)
  *
  * Check to see if the ZFS path provided has the sharenfs option set
  * or not.
  */
 
 int
-sa_zfs_is_shared(char *path)
+sa_zfs_is_shared(sa_handle_t sahandle, char *path)
 {
 	int ret = 0;
 	char *dataset;
@@ -287,7 +288,7 @@
 	char shareopts[ZFS_MAXPROPLEN];
 	libzfs_handle_t *libhandle;
 
-	dataset = get_zfs_dataset(path);
+	dataset = get_zfs_dataset((sa_handle_t)sahandle, path);
 	if (dataset != NULL) {
 	    libhandle = libzfs_init();
 	    if (libhandle != NULL) {
@@ -319,7 +320,7 @@
  */
 
 static sa_group_t
-find_or_create_group(char *groupname, char *proto, int *err)
+find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
 {
 	sa_group_t group;
 	sa_optionset_t optionset;
@@ -331,9 +332,9 @@
 	 * parent. This is to make sure the zfs group has been created
 	 * and to created if it hasn't been.
 	 */
-	group = sa_get_group(groupname);
+	group = sa_get_group(handle, groupname);
 	if (group == NULL) {
-	    group = sa_create_group(groupname, &ret);
+	    group = sa_create_group(handle, groupname, &ret);
 
 	    /* make sure this is flagged as a ZFS group */
 	    if (group != NULL)
@@ -374,7 +375,8 @@
  */
 
 static sa_group_t
-find_or_create_zfs_subgroup(char *groupname, char *optstring, int *err)
+find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname,
+				char *optstring, int *err)
 {
 	sa_group_t group = NULL;
 	sa_group_t zfs;
@@ -382,7 +384,7 @@
 	char *options;
 
 	/* start with the top-level "zfs" group */
-	zfs = sa_get_group("zfs");
+	zfs = sa_get_group(handle, "zfs");
 	*err = SA_OK;
 	if (zfs != NULL) {
 	    for (group = sa_get_sub_group(zfs); group != NULL;
@@ -420,7 +422,7 @@
 }
 
 /*
- * sa_get_zfs_shares(groupname)
+ * sa_get_zfs_shares(handle, groupname)
  *
  * Walk the mnttab for all zfs mounts and determine which are
  * shared. Find or create the appropriate group/sub-group to contain
@@ -431,7 +433,7 @@
  */
 
 int
-sa_get_zfs_shares(char *groupname)
+sa_get_zfs_shares(sa_handle_t handle, char *groupname)
 {
 	sa_group_t group;
 	sa_group_t zfsgroup;
@@ -445,20 +447,22 @@
 	char mountpoint[ZFS_MAXPROPLEN];
 	char *options;
 	size_t count = 0, i;
+	libzfs_handle_t *zfs_libhandle;
 
 	/*
-	 * if we can't access libzfs, don't bother doing anything.
+	 * If we can't access libzfs, don't bother doing anything.
 	 */
+	zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
 	if (zfs_libhandle == NULL)
 	    return (SA_SYSTEM_ERR);
 
-	zfsgroup = find_or_create_group(groupname, "nfs", &err);
+	zfsgroup = find_or_create_group(handle, groupname, "nfs", &err);
 	if (zfsgroup != NULL) {
 		/*
 		 * need to walk the mounted ZFS pools and datasets to
 		 * find shares that are possible.
 		 */
-	    get_all_filesystems(&zlist, &count);
+	    get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
 	    qsort(zlist, count, sizeof (void *), mountpoint_compare);
 
 	    group = zfsgroup;
@@ -494,7 +498,7 @@
 					B_FALSE) == 0 &&
 			strcmp(shareopts, "off") != 0) {
 		    /* it is shared so add to list */
-		    share = sa_find_share(mountpoint);
+		    share = sa_find_share(handle, mountpoint);
 		    err = SA_OK;
 		    if (share != NULL) {
 			/*
@@ -520,7 +524,8 @@
 			 * variable. The real parent not mounted can
 			 * occur if "canmount=off and sharenfs=on".
 			 */
-			    group = find_or_create_zfs_subgroup(sourcestr,
+			    group = find_or_create_zfs_subgroup(handle,
+							sourcestr,
 							shareopts, &doshopt);
 			    if (group != NULL) {
 				share = _sa_add_share(group, mountpoint,
@@ -633,8 +638,9 @@
 	command = malloc(ZFS_MAXPROPLEN * 2);
 	if (command != NULL) {
 	    char *opts = NULL;
-	    char *dataset;
+	    char *dataset = NULL;
 	    FILE *pfile;
+	    sa_handle_impl_t impl_handle;
 	    /* for now, NFS is always available for "zfs" */
 	    if (on) {
 		opts = sa_proto_legacy_format("nfs", group, 1);
@@ -643,7 +649,13 @@
 		    opts = strdup("on");
 		}
 	    }
-	    dataset = get_zfs_dataset(path);
+
+	    impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
+	    if (impl_handle != NULL)
+		dataset = get_zfs_dataset(impl_handle, path);
+	    else
+		ret = SA_SYSTEM_ERR;
+
 	    if (dataset != NULL) {
 		(void) snprintf(command, ZFS_MAXPROPLEN * 2,
 				"%s set sharenfs=\"%s\" %s", COMMAND,
@@ -704,7 +716,14 @@
 		if (sa_is_share(group)) {
 		    path = sa_get_share_attr((sa_share_t)group, "path");
 		    if (path != NULL) {
-			dataset = get_zfs_dataset(path);
+			sa_handle_impl_t impl_handle;
+
+			impl_handle = sa_find_group_handle(group);
+			if (impl_handle != NULL)
+			    dataset = get_zfs_dataset(impl_handle, path);
+			else
+			    ret = SA_SYSTEM_ERR;
+
 			sa_free_attr_string(path);
 		    }
 		} else {
--- a/usr/src/lib/libshare/common/libsharecore.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/libsharecore.c	Wed Mar 28 08:50:43 2007 -0700
@@ -82,14 +82,13 @@
     char *origline;
     int lineno;
 } xfs_sharelist_t;
-static void parse_dfstab(char *, xmlNodePtr);
+static void parse_dfstab(sa_handle_t, char *, xmlNodePtr);
 extern char *get_token(char *);
 static void dfs_free_list(xfs_sharelist_t *);
 /* prototypes */
-void getlegacyconfig(char *, xmlNodePtr *);
+void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
-extern xmlNodePtr _sa_get_next_error(xmlNodePtr);
-extern sa_group_t _sa_create_group(char *);
+extern sa_group_t _sa_create_group(sa_handle_impl_t, char *);
 static void outdfstab(FILE *, xfs_sharelist_t *);
 extern int _sa_remove_optionset(sa_optionset_t);
 extern int set_node_share(void *, char *, char *);
@@ -915,7 +914,7 @@
  */
 
 static void
-parse_dfstab(char *dfstab, xmlNodePtr root)
+parse_dfstab(sa_handle_t handle, char *dfstab, xmlNodePtr root)
 {
 	sa_share_t share;
 	sa_group_t group;
@@ -934,7 +933,7 @@
 	    return;
 	}
 
-	defgroup = sa_get_group("default");
+	defgroup = sa_get_group(handle, "default");
 
 	for (head = list = getdfstab(dfs);
 		list != NULL;
@@ -974,8 +973,8 @@
 		continue;
 	    }
 	    if (list->path != NULL && strlen(list->path) > 0 &&
-		*list->path == '/') {
-		share = sa_find_share(list->path);
+		    *list->path == '/') {
+		share = sa_find_share(handle, list->path);
 		if (share != NULL)
 		    sgroup = sa_get_parent_group(share);
 		else
@@ -991,7 +990,7 @@
 		continue;
 	    }
 	    if (list->group != NULL && strlen(list->group) > 0) {
-		group = sa_get_group(list->group);
+		group = sa_get_group(handle, list->group);
 		defined_group = 1;
 	    } else {
 		group = defgroup;
@@ -1141,7 +1140,7 @@
  */
 
 void
-getlegacyconfig(char *path, xmlNodePtr *root)
+getlegacyconfig(sa_handle_t handle, char *path, xmlNodePtr *root)
 {
 	sa_group_t defgroup;
 
@@ -1157,12 +1156,12 @@
 			 * code add/del via dfstab and we need to
 			 * cleanup SMF.
 			 */
-		    defgroup = sa_get_group("default");
+		    defgroup = sa_get_group(handle, "default");
 		    if (defgroup != NULL) {
 			legacy_removes(defgroup, path);
 		    }
 		    /* parse the dfstab and add anything new */
-		    parse_dfstab(path, *root);
+		    parse_dfstab(handle, path, *root);
 		}
 	    }
 	}
@@ -1244,7 +1243,7 @@
 }
 
 /*
- * parse_sharetab(void)
+ * parse_sharetab(handle)
  *
  * Read the /etc/dfs/sharetab file and see which entries don't exist
  * in the repository. These shares are marked transient.  We also need
@@ -1253,7 +1252,7 @@
  */
 
 int
-parse_sharetab(void)
+parse_sharetab(sa_handle_t handle)
 {
 	xfs_sharelist_t *list, *tmplist;
 	int err = 0;
@@ -1267,11 +1266,11 @@
 	if (list == NULL)
 	    return (legacy);
 
-	lgroup = sa_get_group("default");
+	lgroup = sa_get_group(handle, "default");
 
 	for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) {
 	    group = NULL;
-	    share = sa_find_share(tmplist->path);
+	    share = sa_find_share(handle, tmplist->path);
 	    if (share == NULL) {
 		/*
 		 * this share is transient so needs to be
@@ -1283,7 +1282,7 @@
 		    (groupname = strchr(tmplist->resource, '@')) != NULL) {
 		    /* there is a defined group */
 		    *groupname++ = '\0';
-		    group = sa_get_group(groupname);
+		    group = sa_get_group(handle, groupname);
 		    if (group != NULL) {
 			share = _sa_add_share(group, tmplist->path,
 						SA_SHARE_TRANSIENT, &err);
@@ -1302,12 +1301,14 @@
 						SA_SHARE_TRANSIENT, &err);
 		    }
 		} else {
-		    if (sa_zfs_is_shared(tmplist->path)) {
-			group = sa_get_group("zfs");
+		    if (sa_zfs_is_shared(handle, tmplist->path)) {
+			group = sa_get_group(handle, "zfs");
 			if (group == NULL) {
-			    group = sa_create_group("zfs", &err);
+			    group = sa_create_group(handle, "zfs", &err);
 			    if (group == NULL && err == SA_NO_PERMISSION) {
-				group = _sa_create_group("zfs");
+				group = _sa_create_group(
+						(sa_handle_impl_t)handle,
+						"zfs");
 			    }
 			    if (group != NULL) {
 				(void) sa_create_optionset(group,
@@ -1371,7 +1372,7 @@
  * in a repository.
  */
 int
-gettransients(xmlNodePtr *root)
+gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root)
 {
 	int legacy = 0;
 
@@ -1379,7 +1380,7 @@
 	    if (*root == NULL)
 		*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
 	    if (*root != NULL) {
-		legacy = parse_sharetab();
+		legacy = parse_sharetab(ihandle);
 	    }
 	}
 	return (legacy);
@@ -1418,12 +1419,15 @@
  */
 
 void
-update_legacy_config(void)
+update_legacy_config(sa_handle_t handle)
 {
 	/*
 	 * no longer used -- this is a placeholder in case we need to
 	 * add it back later.
 	 */
+#ifdef lint
+	handle = handle;
+#endif
 }
 
 /*
--- a/usr/src/lib/libshare/common/mapfile-vers	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/mapfile-vers	Wed Mar 28 08:50:43 2007 -0700
@@ -19,13 +19,13 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
 
-SUNWprivate_1.1 {
+SUNWprivate {
     global:
 	sa_get_optionset;
 	sa_create_property;
@@ -104,6 +104,7 @@
 	sa_enable_share;
 	sa_create_group;
 	sa_valid_protocol;
+	sa_find_group_handle;
     local:
 	*;
 };
--- a/usr/src/lib/libshare/common/plugin.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/plugin.c	Wed Mar 28 08:50:43 2007 -0700
@@ -38,6 +38,9 @@
 #include <sys/stat.h>
 #include <dirent.h>
 #include <libintl.h>
+#include <sys/systeminfo.h>
+
+#define	MAXISALEN	257	/* based on sysinfo(2) man page */
 
 /*
  * protocol plugin interface
@@ -85,14 +88,25 @@
 	if (dir != NULL) {
 	    while (ret == SA_OK && (dent = readdir(dir)) != NULL) {
 		char path[MAXPATHLEN];
+		char isa[MAXISALEN];
+
+#if defined(_LP64)
+		if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
+		    isa[0] = '\0';
+#else
+		isa[0] = '\0';
+#endif
 		(void) snprintf(path, MAXPATHLEN,
-				"%s/%s/libshare_%s.so",	SA_LIB_DIR,
-				dent->d_name, dent->d_name);
-		if (stat(path, &st) < 0) {
+				"%s/%s/%s/libshare_%s.so.1",
+				SA_LIB_DIR,
+				dent->d_name,
+				isa,
+				dent->d_name);
+			if (stat(path, &st) < 0) {
 		    /* file doesn't exist, so don't try to map it */
 		    continue;
 		}
-		dlhandle = dlopen(path, RTLD_NOW|RTLD_GLOBAL|RTLD_WORLD);
+		dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY);
 		if (dlhandle != NULL) {
 		    plugin_ops = (struct sa_plugin_ops *)
 					dlsym(dlhandle,	"sa_plugin_ops");
--- a/usr/src/lib/libshare/common/scfutil.c	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/scfutil.c	Wed Mar 28 08:50:43 2007 -0700
@@ -42,6 +42,7 @@
 
 ssize_t scf_max_name_len;
 extern struct sa_proto_plugin *sap_proto_list;
+extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
 
 /*
  * The SMF facility uses some properties that must exist. We want to
@@ -93,7 +94,7 @@
  */
 
 scfutilhandle_t *
-sa_scf_init()
+sa_scf_init(sa_handle_impl_t ihandle)
 {
 	scfutilhandle_t *handle;
 
@@ -103,6 +104,7 @@
 
 	handle = calloc(1, sizeof (scfutilhandle_t));
 	if (handle != NULL) {
+	    ihandle->scfhandle = handle;
 	    handle->scf_state = SCH_STATE_INITIALIZING;
 	    handle->handle = scf_handle_create(SCF_VERSION);
 	    if (handle->handle != NULL) {
@@ -123,7 +125,8 @@
 			    char **protolist;
 			    int numprotos, i;
 			    sa_group_t defgrp;
-			    defgrp = sa_create_group("default", NULL);
+			    defgrp = sa_create_group((sa_handle_t)ihandle,
+							"default", NULL);
 			    if (defgrp != NULL) {
 				numprotos = sa_get_protocols(&protolist);
 				for (i = 0; i < numprotos; i++) {
@@ -539,14 +542,14 @@
  */
 
 static sa_share_t
-find_share_by_id(char *shareid)
+find_share_by_id(sa_handle_t handle, char *shareid)
 {
 	sa_group_t group;
 	sa_share_t share = NULL;
 	char *id = NULL;
 	int done = 0;
 
-	for (group = sa_get_group(NULL); group != NULL && !done;
+	for (group = sa_get_group(handle, NULL); group != NULL && !done;
 		group = sa_get_next_group(group)) {
 		for (share = sa_get_share(group, NULL); share != NULL;
 			share = sa_get_next_share(share)) {
@@ -577,7 +580,7 @@
 
 static int
 sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
-			scf_propertygroup_t *pg, char *id)
+			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
 {
 	xmlNodePtr node;
 	char *name;
@@ -638,7 +641,7 @@
 	 * match.
 	 */
 
-	share = find_share_by_id(id);
+	share = find_share_by_id(sahandle, id);
 	if (share == NULL)
 	    return (SA_BAD_PATH);
 
@@ -717,7 +720,7 @@
 
 static int
 sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
-			scf_instance_t *instance)
+			scf_instance_t *instance, sa_handle_t sahandle)
 {
 	char *buff;
 	xmlNodePtr node;
@@ -857,7 +860,7 @@
 					ret = sa_share_props_from_pgroup(node,
 								handle,
 								handle->pg,
-								buff);
+								buff, sahandle);
 				    }
 				}
 			    }
@@ -924,14 +927,15 @@
 
 
 /*
- * sa_get_config(handle, root, doc)
+ * sa_get_config(handle, root, doc, sahandlec)
  *
  * walk the SMF repository for /network/shares/group and find all the
  * instances. These become group names.  Then add the XML structure
  * below the groups based on property groups and properties.
  */
 int
-sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc)
+sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc,
+		sa_handle_t sahandle)
 {
 	int ret = SA_OK;
 	scf_instance_t *instance;
@@ -952,7 +956,8 @@
 						sizeof (buff)) > 0) {
 			if (strcmp(buff, "default") == 0)
 			    sa_extract_defaults(*root, handle, instance);
-			ret = sa_extract_group(*root, handle, instance);
+			ret = sa_extract_group(*root, handle, instance,
+						sahandle);
 		    }
 		}
 	    }
--- a/usr/src/lib/libshare/common/scfutil.h	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/lib/libshare/common/scfutil.h	Wed Mar 28 08:50:43 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,7 +55,8 @@
 
 extern void sa_scf_fini(scfutilhandle_t *);
 extern scfutilhandle_t *sa_scf_init();
-extern int sa_get_config(scfutilhandle_t *, xmlNodePtr *, xmlDocPtr *);
+extern int sa_get_config(scfutilhandle_t *, xmlNodePtr *, xmlDocPtr *,
+				sa_handle_t);
 extern int sa_get_instance(scfutilhandle_t *, char *);
 extern int sa_create_instance(scfutilhandle_t *, char *);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+MSGFILES = 	libshare_nfs.c
+POFILE  =	libshare_nfs.po
+
+all	:=	TARGET= all
+clean	:=	TARGET= clean
+clobber	:=	TARGET= clobber
+install	:=	TARGET= install
+lint	:=	TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint:	$(SUBDIRS)
+
+$(POFILE): 	$(MSGFILES)
+	$(BUILDPO.msgfiles)
+
+_msg:	$(MSGDOMAINPOFILE)
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
+include ../../../Makefile.msg.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/Makefile.com	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY =	libshare_nfs.a
+VERS =		.1
+NFSLIB_DIR	= $(SRC)/cmd/fs.d/nfs/lib
+
+LIBOBJS =	libshare_nfs.o
+OTHOBJS =	nfs_sec.o nfslog_config.o nfslogtab.o
+OBJECTS =	$(LIBOBJS) $(OTHOBJS)
+
+include ../../../Makefile.lib
+
+ROOTLIBDIR =	$(ROOT)/usr/lib/fs/nfs
+ROOTLIBDIR64 =	$(ROOT)/usr/lib/fs/nfs/$(MACH64)
+
+LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c)
+# we don't want to lint the sources for OTHOBJS since they are pre-existing files
+# that are not lint free.
+lintcheck := SRCS = $(LIBSRCS)
+
+LIBS =		$(DYNLIB)
+LDLIBS +=	-lshare -lnsl -lscf -lumem -lc
+all install := LDLIBS += -lxml2
+
+#add nfs/lib directory as part of the include path
+CFLAGS +=	$(CCVERBOSE)
+CPPFLAGS +=	-D_REENTRANT -I$(NFSLIB_DIR) -I/usr/include/libxml2 \
+			-I$(SRCDIR)/../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all
+
+lint: lintcheck
+
+pics/%.o:       $(NFSLIB_DIR)/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/amd64/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/i386/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/inc.flg	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+echo_file usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
+echo_file usr/src/cmd/fs.d/nfs/lib/nfslog_config.c
+echo_file usr/src/cmd/fs.d/nfs/lib/nfslogtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,2722 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * NFS specific functions
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zone.h>
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include "libshare.h"
+#include "libshare_impl.h"
+#include <nfs/export.h>
+#include <pwd.h>
+#include <limits.h>
+#include <libscf.h>
+#include "nfslog_config.h"
+#include "nfslogtab.h"
+#include "libshare_nfs.h"
+#include <rpcsvc/daemon_utils.h>
+#include <nfs/nfs.h>
+
+/* should really be in some global place */
+#define	DEF_WIN	30000
+#define	OPT_CHUNK	1024
+
+int debug = 0;
+
+
+/* internal functions */
+static int nfs_init();
+static void nfs_fini();
+static int nfs_enable_share(sa_share_t);
+static int nfs_disable_share(char *);
+static int nfs_validate_property(sa_property_t, sa_optionset_t);
+static int nfs_validate_security_mode(char *);
+static int nfs_is_security_opt(char *);
+static int nfs_parse_legacy_options(sa_group_t, char *);
+static char *nfs_format_options(sa_group_t, int);
+static int nfs_set_proto_prop(sa_property_t);
+static sa_protocol_properties_t nfs_get_proto_set();
+static char *nfs_get_status();
+static char *nfs_space_alias(char *);
+
+/*
+ * ops vector that provides the protocol specific info and operations
+ * for share management.
+ */
+
+struct sa_plugin_ops sa_plugin_ops = {
+	SA_PLUGIN_VERSION,
+	"nfs",
+	nfs_init,
+	nfs_fini,
+	nfs_enable_share,
+	nfs_disable_share,
+	nfs_validate_property,
+	nfs_validate_security_mode,
+	nfs_is_security_opt,
+	nfs_parse_legacy_options,
+	nfs_format_options,
+	nfs_set_proto_prop,
+	nfs_get_proto_set,
+	nfs_get_status,
+	nfs_space_alias,
+	NULL,
+	NULL
+};
+
+/*
+ * list of support services needed
+ * defines should come from head/rpcsvc/daemon_utils.h
+ */
+
+static char *service_list_default[] =
+	{ STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NULL };
+static char *service_list_logging[] =
+	{ STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, NULL };
+
+/*
+ * option definitions.  Make sure to keep the #define for the option
+ * index just before the entry it is the index for. Changing the order
+ * can cause breakage.  E.g OPT_RW is index 1 and must precede the
+ * line that includes the SHOPT_RW and OPT_RW entries.
+ */
+
+struct option_defs optdefs[] = {
+#define	OPT_RO		0
+	{SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST},
+#define	OPT_RW		1
+	{SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST},
+#define	OPT_ROOT	2
+	{SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST},
+#define	OPT_SECURE	3
+	{SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED},
+#define	OPT_ANON	4
+	{SHOPT_ANON, OPT_ANON, OPT_TYPE_USER},
+#define	OPT_WINDOW	5
+	{SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER},
+#define	OPT_NOSUID	6
+	{SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN},
+#define	OPT_ACLOK	7
+	{SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN},
+#define	OPT_NOSUB	8
+	{SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN},
+#define	OPT_SEC		9
+	{SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY},
+#define	OPT_PUBLIC	10
+	{SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY},
+#define	OPT_INDEX	11
+	{SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE},
+#define	OPT_LOG		12
+	{SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG},
+#define	OPT_CKSUM	13
+	{SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET},
+#ifdef VOLATILE_FH_TEST	/* XXX added for testing volatile fh's only */
+#define	OPT_VOLFH	14
+	{SHOPT_VOLFH, OPT_VOLFH},
+#endif /* VOLATILE_FH_TEST */
+	NULL
+};
+
+/*
+ * list of properties that are related to security flavors.
+ */
+static char *seclist[] = {
+	SHOPT_RO,
+	SHOPT_RW,
+	SHOPT_ROOT,
+	SHOPT_WINDOW,
+	NULL
+};
+
+/* structure for list of securities */
+struct securities {
+	sa_security_t security;
+	struct securities *next;
+};
+
+/*
+ * findopt(name)
+ *
+ * Lookup option "name" in the option table and return the table
+ * index.
+ */
+
+static int
+findopt(char *name)
+{
+	int i;
+	if (name != NULL) {
+	    for (i = 0; optdefs[i].tag != NULL; i++) {
+		if (strcmp(optdefs[i].tag, name) == 0)
+		    return (i);
+	    }
+	}
+	return (-1);
+}
+
+/*
+ * gettype(name)
+ *
+ * Return the type of option "name".
+ */
+
+static int
+gettype(char *name)
+{
+	int optdef;
+
+	optdef = findopt(name);
+	if (optdef != -1)
+	    return (optdefs[optdef].type);
+	return (OPT_TYPE_ANY);
+}
+
+/*
+ * nfs_validate_security_mode(mode)
+ *
+ * is the specified mode string a valid one for use with NFS?
+ */
+
+static int
+nfs_validate_security_mode(char *mode)
+{
+	seconfig_t secinfo;
+	int err;
+
+	(void) memset(&secinfo, '\0', sizeof (secinfo));
+	err = nfs_getseconfig_byname(mode, &secinfo);
+	if (err == SC_NOERROR)
+	    return (1);
+	return (0);
+}
+
+/*
+ * nfs_is_security_opt(tok)
+ *
+ * check to see if tok represents an option that is only valid in some
+ * security flavor.
+ */
+
+static int
+nfs_is_security_opt(char *tok)
+{
+	int i;
+
+	for (i = 0; seclist[i] != NULL; i++) {
+	    if (strcmp(tok, seclist[i]) == 0)
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * find_security(seclist, sec)
+ *
+ * Walk the current list of security flavors and return true if it is
+ * present, else return false.
+ */
+
+static int
+find_security(struct securities *seclist, sa_security_t sec)
+{
+	while (seclist != NULL) {
+	    if (seclist->security == sec)
+		return (1);
+	    seclist = seclist->next;
+	}
+	return (0);
+}
+
+/*
+ * make_security_list(group, securitymodes, proto)
+ *	go through the list of securitymodes and add them to the
+ *	group's list of security optionsets. We also keep a list of
+ *	those optionsets so we don't have to find them later. All of
+ *	these will get copies of the same properties.
+ */
+
+static struct securities *
+make_security_list(sa_group_t group, char *securitymodes, char *proto)
+{
+	char *tok, *next = NULL;
+	struct securities *curp, *headp = NULL, *prev;
+	sa_security_t check;
+	int freetok = 0;
+
+	for (tok = securitymodes; tok != NULL; tok = next) {
+	    next = strchr(tok, ':');
+	    if (next != NULL)
+		*next++ = '\0';
+	    if (strcmp(tok, "default") == 0) {
+		/* resolve default into the real type */
+		tok = nfs_space_alias(tok);
+		freetok = 1;
+	    }
+	    check = sa_get_security(group, tok, proto);
+
+	    /* add to the security list if it isn't there already */
+	    if (check == NULL || !find_security(headp, check)) {
+		curp = (struct securities *)calloc(1,
+						sizeof (struct securities));
+		if (curp != NULL) {
+		    if (check == NULL) {
+			curp->security = sa_create_security(group, tok,
+								proto);
+		    } else {
+			curp->security = check;
+		    }
+			/*
+			 * note that the first time through the loop,
+			 * headp will be NULL and prev will be
+			 * undefined.  Since headp is NULL, we set
+			 * both it and prev to the curp (first
+			 * structure to be allocated).
+			 *
+			 * later passes through the loop will have
+			 * headp not being NULL and prev will be used
+			 * to allocate at the end of the list.
+			 */
+		    if (headp == NULL) {
+			headp = curp;
+			prev = curp;
+		    } else {
+			prev->next = curp;
+			prev = curp;
+		    }
+		}
+	    }
+
+	    if (freetok) {
+		freetok = 0;
+		sa_free_attr_string(tok);
+	    }
+	}
+	return (headp);
+}
+
+static void
+free_security_list(struct securities *sec)
+{
+	struct securities *next;
+	if (sec != NULL) {
+	    for (next = sec->next; sec != NULL; sec = next) {
+		next = sec->next;
+		free(sec);
+	    }
+	}
+}
+
+/*
+ * nfs_alistcat(str1, str2, sep)
+ *
+ * concatenate str1 and str2 into a new string using sep as a separate
+ * character. If memory allocation fails, return NULL;
+ */
+
+static char *
+nfs_alistcat(char *str1, char *str2, char sep)
+{
+	char *newstr;
+	size_t len;
+
+	len = strlen(str1) + strlen(str2) + 2;
+	newstr = (char *)malloc(len);
+	if (newstr != NULL)
+	    (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2);
+	return (newstr);
+}
+
+/*
+ * add_security_prop(sec, name, value, persist)
+ *
+ * Add the property to the securities structure. This accumulates
+ * properties for as part of parsing legacy options.
+ */
+
+static int
+add_security_prop(struct securities *sec, char *name, char *value,
+			int persist, int iszfs)
+{
+	sa_property_t prop;
+	int ret = SA_OK;
+
+	for (; sec != NULL; sec = sec->next) {
+	    if (value == NULL) {
+		if (strcmp(name, SHOPT_RW) == 0 || strcmp(name, SHOPT_RO) == 0)
+		    value = "*";
+		else
+		    value = "true";
+	    }
+
+		/*
+		 * Get the existing property, if it exists, so we can
+		 * determine what to do with it. The ro/rw/root
+		 * properties can be merged if multiple instances of
+		 * these properies are given. For example, if "rw"
+		 * exists with a value "host1" and a later token of
+		 * rw="host2" is seen, the values are merged into a
+		 * single rw="host1:host2".
+		 */
+	    prop = sa_get_property(sec->security, name);
+
+	    if (prop != NULL) {
+		char *oldvalue;
+		char *newvalue;
+
+		/*
+		 * The security options of ro/rw/root might appear
+		 * multiple times. If they do, the values need to be
+		 * merged into an access list. If it was previously
+		 * empty, the new value alone is added.
+		 */
+		oldvalue = sa_get_property_attr(prop, "value");
+		if (oldvalue != NULL) {
+			/*
+			 * The general case is to concatenate the new
+			 * value onto the old value for multiple
+			 * rw(ro/root) properties. A special case
+			 * exists when either the old or new is the
+			 * "all" case. In the special case, if both
+			 * are "all", then it is "all", else if one is
+			 * an access-list, that replaces the "all".
+			 */
+		    if (strcmp(oldvalue, "*") == 0) {
+			/* Replace old value with new value. */
+			newvalue = strdup(value);
+		    } else if (strcmp(value, "*") == 0) {
+			/* Keep old value and ignore the new value. */
+			newvalue = NULL;
+		    } else {
+			/* Make a new list of old plus new access-list. */
+			newvalue = nfs_alistcat(oldvalue, value, ':');
+		    }
+
+		    if (newvalue != NULL) {
+			(void) sa_remove_property(prop);
+			prop = sa_create_property(name, newvalue);
+			ret = sa_add_property(sec->security, prop);
+			free(newvalue);
+		    }
+		    if (oldvalue != NULL)
+			sa_free_attr_string(oldvalue);
+		}
+	    } else {
+		prop = sa_create_property(name, value);
+		ret = sa_add_property(sec->security, prop);
+	    }
+	    if (ret == SA_OK && !iszfs) {
+		ret = sa_commit_properties(sec->security, !persist);
+	    }
+	}
+	return (ret);
+}
+
+/*
+ * check to see if group/share is persistent.
+ */
+static int
+is_persistent(sa_group_t group)
+{
+	char *type;
+	int persist = 1;
+
+	type = sa_get_group_attr(group, "type");
+	if (type != NULL && strcmp(type, "persist") != 0)
+	    persist = 0;
+	if (type != NULL)
+	    sa_free_attr_string(type);
+	return (persist);
+}
+
+/*
+ * invalid_security(options)
+ *
+ * search option string for any invalid sec= type.
+ * return true (1) if any are not valid else false (0)
+ */
+static int
+invalid_security(char *options)
+{
+	char *copy, *base, *token, *value;
+	int ret = 0;
+
+	copy = strdup(options);
+	token = base = copy;
+	while (token != NULL && ret == 0) {
+	    token = strtok(base, ",");
+	    base = NULL;
+	    if (token != NULL) {
+		value = strchr(token, '=');
+		if (value != NULL)
+		    *value++ = '\0';
+		if (strcmp(token, "sec") == 0) {
+		    /* have security flavors so check them */
+		    char *tok, *next;
+		    for (next = NULL, tok = value; tok != NULL; tok = next) {
+			next = strchr(tok, ':');
+			if (next != NULL)
+			    *next++ = '\0';
+			ret = !nfs_validate_security_mode(tok);
+			if (ret)
+			    break;
+		    }
+		}
+	    }
+	}
+	if (copy != NULL)
+	    free(copy);
+	return (ret);
+}
+
+/*
+ * nfs_parse_legacy_options(group, options)
+ *
+ * Parse the old style options into internal format and store on the
+ * specified group.  Group could be a share for full legacy support.
+ */
+
+static int
+nfs_parse_legacy_options(sa_group_t group, char *options)
+{
+	char *dup = strdup(options);
+	char *base;
+	char *token;
+	sa_optionset_t optionset;
+	struct securities *security_list = NULL;
+	sa_property_t prop;
+	int ret = SA_OK;
+	int iszfs = 0;
+	sa_group_t parent;
+	int persist = 0;
+	char *lasts;
+
+	/* do we have an existing optionset? */
+	optionset = sa_get_optionset(group, "nfs");
+	if (optionset == NULL) {
+	    /* didn't find existing optionset so create one */
+	    optionset = sa_create_optionset(group, "nfs");
+	} else {
+		/*
+		 * have an existing optionset so we need to compare
+		 * options in order to detect errors. For now, we
+		 * assume that the first optionset is the correct one
+		 * and the others will be the same. This needs to be
+		 * fixed before the final code is ready.
+		 */
+	    return (ret);
+	}
+
+	if (strcmp(options, SHOPT_RW) == 0) {
+		/*
+		 * there is a special case of only the option "rw"
+		 * being the default option. We don't have to do
+		 * anything.
+		 */
+	    return (ret);
+	}
+
+	/*
+	 * check if security types are present and validate them. If
+	 * any are not legal, fail.
+	 */
+
+	if (invalid_security(options)) {
+	    return (SA_INVALID_SECURITY);
+	}
+
+	/*
+	 * in order to not attempt to change ZFS properties unless
+	 * absolutely necessary, we never do it in the legacy parsing.
+	 */
+	if (sa_is_share(group)) {
+	    char *zfs;
+	    parent = sa_get_parent_group(group);
+	    if (parent != NULL) {
+		zfs = sa_get_group_attr(parent, "zfs");
+		if (zfs != NULL) {
+		    sa_free_attr_string(zfs);
+		    iszfs++;
+		}
+	    }
+	} else {
+	    iszfs = sa_group_is_zfs(group);
+	}
+
+	/*
+	 * we need to step through each option in the string and then
+	 * add either the option or the security option as needed. If
+	 * this is not a persistent share, don't commit to the
+	 * repository. If there is an error, we also want to abort the
+	 * processing and report it.
+	 */
+	persist = is_persistent(group);
+	base = dup;
+	token = dup;
+	lasts = NULL;
+	while (token != NULL && ret == SA_OK) {
+	    ret = SA_OK;
+	    token = strtok_r(base, ",", &lasts);
+	    base = NULL;
+	    if (token != NULL) {
+		char *value;
+		/*
+		 * if the option has a value, it will have an '=' to
+		 * separate the name from the value. The following
+		 * code will result in value != NULL and token
+		 * pointing to just the name if there is a value.
+		 */
+		value = strchr(token, '=');
+		if (value != NULL) {
+		    *value++ = '\0';
+		}
+		if (strcmp(token, "sec") == 0 || strcmp(token, "secure") == 0) {
+			/*
+			 * Once in security parsing, we only
+			 * do security. We do need to move
+			 * between the security node and the
+			 * toplevel. The security tag goes on
+			 * the root while the following ones
+			 * go on the security.
+			 */
+		    if (security_list != NULL) {
+			/* have an old list so close it and start the new */
+			free_security_list(security_list);
+		    }
+		    if (strcmp(token, "secure") == 0) {
+			value = "dh";
+		    } else {
+			if (value == NULL) {
+			    ret = SA_SYNTAX_ERR;
+			    break;
+			}
+		    }
+		    security_list = make_security_list(group, value, "nfs");
+		} else {
+			/*
+			 * Note that the "old" syntax allowed a
+			 * default security model This must be
+			 * accounted for and internally converted to
+			 * "standard" security structure.
+			 */
+		    if (nfs_is_security_opt(token)) {
+			if (security_list == NULL) {
+				/*
+				 * need to have a security option. This
+				 * will be "closed" when a defined "sec="
+				 * option is seen. This is technically an
+				 * error but will be allowed with warning.
+				 */
+			    security_list = make_security_list(group,
+								"default",
+								"nfs");
+			}
+			if (security_list != NULL) {
+			    ret = add_security_prop(security_list, token,
+							value, persist,
+							iszfs);
+			} else {
+			    ret = SA_NO_MEMORY;
+			}
+		    } else {
+			/* regular options */
+			if (value == NULL) {
+			    if (strcmp(token, SHOPT_RW) == 0 ||
+				strcmp(token, SHOPT_RO) == 0)
+				value = "*";
+			    else if (strcmp(token, SHOPT_LOG) == 0)
+				value = "global";
+			    else
+				value = "true";
+			}
+			prop = sa_create_property(token, value);
+			ret = sa_add_property(optionset, prop);
+			if (ret != SA_OK) {
+			    break;
+			}
+			if (!iszfs) {
+			    ret = sa_commit_properties(optionset, !persist);
+			}
+		    }
+		}
+	    }
+	}
+	if (security_list != NULL)
+	    free_security_list(security_list);
+	if (dup != NULL)
+	    free(dup);
+	return (ret);
+}
+
+/*
+ * is_a_number(number)
+ *
+ * is the string a number in one of the forms we want to use?
+ */
+
+static int
+is_a_number(char *number)
+{
+	int ret = 1;
+	int hex = 0;
+
+	if (strncmp(number, "0x", 2) == 0) {
+	    number += 2;
+	    hex = 1;
+	} else if (*number == '-')
+	    number++; /* skip the minus */
+
+	while (ret == 1 && *number != '\0') {
+	    if (hex) {
+		ret = isxdigit(*number++);
+	    } else {
+		ret = isdigit(*number++);
+	    }
+	}
+	return (ret);
+}
+
+/*
+ * Look for the specified tag in the configuration file. If it is found,
+ * enable logging and set the logging configuration information for exp.
+ */
+static void
+configlog(struct exportdata *exp, char *tag)
+{
+	nfsl_config_t *configlist = NULL, *configp;
+	int error = 0;
+	char globaltag[] = DEFAULTTAG;
+
+	/*
+	 * Sends config errors to stderr
+	 */
+	nfsl_errs_to_syslog = B_FALSE;
+
+	/*
+	 * get the list of configuration settings
+	 */
+	error = nfsl_getconfig_list(&configlist);
+	if (error) {
+		(void) fprintf(stderr,
+				dgettext(TEXT_DOMAIN,
+					"Cannot get log configuration: %s\n"),
+				strerror(error));
+	}
+
+	if (tag == NULL)
+		tag = globaltag;
+	if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) {
+		nfsl_freeconfig_list(&configlist);
+		(void) fprintf(stderr,
+				dgettext(TEXT_DOMAIN,
+					"No tags matching \"%s\"\n"), tag);
+		/* bad configuration */
+		error = ENOENT;
+		goto err;
+	}
+
+	if ((exp->ex_tag = strdup(tag)) == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+	if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+	exp->ex_flags |= EX_LOG;
+	if (configp->nc_rpclogpath != NULL)
+		exp->ex_flags |= EX_LOG_ALLOPS;
+out:
+	if (configlist != NULL)
+	    nfsl_freeconfig_list(&configlist);
+
+err:
+	if (error != 0) {
+		if (exp->ex_flags != NULL)
+			free(exp->ex_tag);
+		if (exp->ex_log_buffer != NULL)
+			free(exp->ex_log_buffer);
+		(void) fprintf(stderr,
+				dgettext(TEXT_DOMAIN,
+					"Cannot set log configuration: %s\n"),
+				strerror(error));
+	}
+}
+
+/*
+ * fill_export_from_optionset(export, optionset)
+ *
+ * In order to share, we need to set all the possible general options
+ * into the export structure. Share info will be filled in by the
+ * caller. Various property values get turned into structure specific
+ * values.
+ */
+
+static int
+fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
+{
+	sa_property_t option;
+	int ret = SA_OK;
+
+	for (option = sa_get_property(optionset, NULL);
+		option != NULL; option = sa_get_next_property(option)) {
+	    char *name;
+	    char *value;
+	    uint32_t val;
+
+	/*
+	 * since options may be set/reset multiple times, always do an
+	 * explicit set or clear of the option. This allows defaults
+	 * to be set and then the protocol specifici to override.
+	 */
+
+	    name = sa_get_property_attr(option, "type");
+	    value = sa_get_property_attr(option, "value");
+	    switch (findopt(name)) {
+	    case OPT_ANON:
+		if (value != NULL && is_a_number(value)) {
+		    val = strtoul(value, NULL, 0);
+		} else {
+		    struct passwd *pw;
+		    pw = getpwnam(value != NULL ? value : "nobody");
+		    if (pw != NULL) {
+			val = pw->pw_uid;
+		    } else {
+			val = UID_NOBODY;
+		    }
+		    endpwent();
+		}
+		export->ex_anon = val;
+		break;
+	    case OPT_NOSUID:
+		if (value != NULL &&
+		    (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0))
+		    export->ex_flags |= EX_NOSUID;
+		else
+		    export->ex_flags &= ~EX_NOSUID;
+		break;
+	    case OPT_ACLOK:
+		if (value != NULL &&
+		    (strcasecmp(value, "true") == 0 ||
+			strcmp(value, "1") == 0))
+		    export->ex_flags |= EX_ACLOK;
+		else
+		    export->ex_flags &= ~EX_ACLOK;
+		break;
+	    case OPT_NOSUB:
+		if (value != NULL &&
+		    (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0))
+		    export->ex_flags |= EX_NOSUB;
+		else
+		    export->ex_flags &= ~EX_NOSUB;
+		break;
+	    case OPT_PUBLIC:
+		if (value != NULL &&
+		    (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0))
+		    export->ex_flags |= EX_PUBLIC;
+		else
+		    export->ex_flags &= ~EX_PUBLIC;
+		break;
+	    case OPT_INDEX:
+		if (value != NULL &&
+		    (strcmp(value, "..") == 0 || strchr(value, '/') != NULL)) {
+		    /* this is an error */
+		    (void) printf(dgettext(TEXT_DOMAIN,
+					    "NFS: index=\"%s\" not valid;"
+					    "must be a filename.\n"),
+			    value);
+		    break;
+		}
+		if (value != NULL && *value != '\0' &&
+			strcmp(value, ".") != 0) {
+		    /* valid index file string */
+		    if (export->ex_index != NULL) {
+			/* left over from "default" */
+			free(export->ex_index);
+		    }
+		    export->ex_index = strdup(value); /* remember to free */
+		    if (export->ex_index == NULL) {
+			(void) printf(dgettext(TEXT_DOMAIN,
+						"NFS: out of memory setting "
+						"index property\n"));
+			break;
+		    }
+		    export->ex_flags |= EX_INDEX;
+		}
+		break;
+	    case OPT_LOG:
+		if (value == NULL)
+		    value = strdup("global");
+		if (value != NULL)
+		    configlog(export, strlen(value) ? value : "global");
+		break;
+	    case OPT_CKSUM:
+		/* TBD: not ready yet */
+		break;
+	    default:
+		/* have a syntactic error */
+		(void) printf(dgettext(TEXT_DOMAIN,
+					"NFS: unrecognized option %s=%s\n"),
+			name, value != NULL ? value : "");
+		break;
+	    }
+	    if (name != NULL)
+		sa_free_attr_string(name);
+	    if (value != NULL)
+		sa_free_attr_string(value);
+	}
+	return (ret);
+}
+
+/*
+ * cleanup_export(export)
+ *
+ * Cleanup the allocated areas so we don't leak memory
+ */
+
+static void
+cleanup_export(struct exportdata *export)
+{
+	int i;
+
+	if (export->ex_index != NULL)
+	    free(export->ex_index);
+	if (export->ex_secinfo != NULL) {
+	    for (i = 0; i < export->ex_seccnt; i++)
+		if (export->ex_secinfo[i].s_rootnames != NULL) {
+		    free(export->ex_secinfo[i].s_rootnames);
+		}
+	    free(export->ex_secinfo);
+	}
+}
+
+/*
+ * Given a seconfig entry and a colon-separated
+ * list of names, allocate an array big enough
+ * to hold the root list, then convert each name to
+ * a principal name according to the security
+ * info and assign it to an array element.
+ * Return the array and its size.
+ */
+static caddr_t *
+get_rootnames(seconfig_t *sec, char *list, int *count)
+{
+	caddr_t *a;
+	int c, i;
+	char *host, *p;
+
+	/*
+	 * Count the number of strings in the list.
+	 * This is the number of colon separators + 1.
+	 */
+	c = 1;
+	for (p = list; *p; p++)
+		if (*p == ':')
+			c++;
+	*count = c;
+
+	a = (caddr_t *)malloc(c * sizeof (char *));
+	if (a == NULL) {
+		(void) printf(dgettext(TEXT_DOMAIN,
+					"get_rootnames: no memory\n"));
+	} else {
+	    for (i = 0; i < c; i++) {
+		host = strtok(list, ":");
+		if (!nfs_get_root_principal(sec, host, &a[i])) {
+		    free(a);
+		    a = NULL;
+		    break;
+		}
+		list = NULL;
+	    }
+	}
+
+	return (a);
+}
+
+/*
+ * fill_security_from_secopts(sp, secopts)
+ *
+ * Fill the secinfo structure from the secopts optionset.
+ */
+
+static int
+fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts)
+{
+	sa_property_t prop;
+	char *type;
+	int longform;
+	int err = SC_NOERROR;
+
+	type = sa_get_security_attr(secopts, "sectype");
+	if (type != NULL) {
+	    /* named security type needs secinfo to be filled in */
+	    err = nfs_getseconfig_byname(type, &sp->s_secinfo);
+	    sa_free_attr_string(type);
+	    if (err != SC_NOERROR)
+		return (err);
+	} else {
+	    /* default case */
+	    err = nfs_getseconfig_default(&sp->s_secinfo);
+	    if (err != SC_NOERROR)
+		return (err);
+	}
+
+	err = SA_OK;
+	for (prop = sa_get_property(secopts, NULL);
+		prop != NULL && err == SA_OK;
+		prop = sa_get_next_property(prop)) {
+	    char *name;
+	    char *value;
+
+	    name = sa_get_property_attr(prop, "type");
+	    value = sa_get_property_attr(prop, "value");
+
+	    longform = value != NULL && strcmp(value, "*") != 0;
+
+	    switch (findopt(name)) {
+	    case OPT_RO:
+		sp->s_flags |= longform ? M_ROL : M_RO;
+		break;
+	    case OPT_RW:
+		sp->s_flags |= longform ? M_RWL : M_RW;
+		break;
+	    case OPT_ROOT:
+		sp->s_flags |= M_ROOT;
+		/*
+		 * if we are using AUTH_UNIX, handle like other things
+		 * such as RO/RW
+		 */
+		if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX)
+		    continue;
+		/* not AUTH_UNIX */
+		if (value != NULL) {
+		    sp->s_rootnames = get_rootnames(&sp->s_secinfo, value,
+							&sp->s_rootcnt);
+		    if (sp->s_rootnames == NULL) {
+			err = SA_BAD_VALUE;
+			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+							"Bad root list\n"));
+		    }
+		}
+		break;
+	    case OPT_WINDOW:
+		if (value != NULL) {
+		    sp->s_window = atoi(value);
+		    if (sp->s_window < 0)
+			sp->s_window = DEF_WIN; /* just in case */
+		}
+		break;
+	    default:
+		break;
+	    }
+	    if (name != NULL)
+		sa_free_attr_string(name);
+	    if (value != NULL)
+		sa_free_attr_string(value);
+	}
+	/* if rw/ro options not set, use default of RW */
+	if ((sp->s_flags & NFS_RWMODES) == 0)
+	    sp->s_flags |= M_RW;
+	return (err);
+}
+
+/*
+ * This is for testing only
+ * It displays the export structure that
+ * goes into the kernel.
+ */
+static void
+printarg(char *path, struct exportdata *ep)
+{
+	int i, j;
+	struct secinfo *sp;
+
+	if (debug == 0)
+	    return;
+
+	(void) printf("%s:\n", path);
+	(void) printf("\tex_version = %d\n", ep->ex_version);
+	(void) printf("\tex_path = %s\n", ep->ex_path);
+	(void) printf("\tex_pathlen = %ld\n", (ulong_t)ep->ex_pathlen);
+	(void) printf("\tex_flags: (0x%02x) ", ep->ex_flags);
+	if (ep->ex_flags & EX_NOSUID)
+		(void) printf("NOSUID ");
+	if (ep->ex_flags & EX_ACLOK)
+		(void) printf("ACLOK ");
+	if (ep->ex_flags & EX_PUBLIC)
+		(void) printf("PUBLIC ");
+	if (ep->ex_flags & EX_NOSUB)
+		(void) printf("NOSUB ");
+	if (ep->ex_flags & EX_LOG)
+		(void) printf("LOG ");
+	if (ep->ex_flags & EX_LOG_ALLOPS)
+		(void) printf("LOG_ALLOPS ");
+	if (ep->ex_flags == 0)
+		(void) printf("(none)");
+	(void) 	printf("\n");
+	if (ep->ex_flags & EX_LOG) {
+		(void) printf("\tex_log_buffer = %s\n",
+			(ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)"));
+		(void) printf("\tex_tag = %s\n",
+				(ep->ex_tag ? ep->ex_tag : "(NULL)"));
+	}
+	(void) printf("\tex_anon = %d\n", ep->ex_anon);
+	(void) printf("\tex_seccnt = %d\n", ep->ex_seccnt);
+	(void) printf("\n");
+	for (i = 0; i < ep->ex_seccnt; i++) {
+		sp = &ep->ex_secinfo[i];
+		(void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name);
+		(void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags);
+		if (sp->s_flags & M_ROOT) (void) printf("M_ROOT ");
+		if (sp->s_flags & M_RO) (void) printf("M_RO ");
+		if (sp->s_flags & M_ROL) (void) printf("M_ROL ");
+		if (sp->s_flags & M_RW) (void) printf("M_RW ");
+		if (sp->s_flags & M_RWL) (void) printf("M_RWL ");
+		if (sp->s_flags == 0) (void) printf("(none)");
+		(void) printf("\n");
+		(void) printf("\t\ts_window = %d\n", sp->s_window);
+		(void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt);
+		(void) fflush(stdout);
+		for (j = 0; j < sp->s_rootcnt; j++)
+			(void) printf("%s ", sp->s_rootnames[j] ?
+					sp->s_rootnames[j] : "<null>");
+		(void) printf("\n\n");
+	}
+}
+
+/*
+ * count_security(opts)
+ *
+ * Count the number of security types (flavors). The optionset has
+ * been populated with the security flavors as a holding mechanism.
+ * We later use this number to allocate data structures.
+ */
+
+static int
+count_security(sa_optionset_t opts)
+{
+	int count = 0;
+	sa_property_t prop;
+	if (opts != NULL) {
+	    for (prop = sa_get_property(opts, NULL); prop != NULL;
+		prop = sa_get_next_property(prop)) {
+		count++;
+	    }
+	}
+	return (count);
+}
+
+/*
+ * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep)
+ *
+ * provides a mechanism to format NFS properties into legacy output
+ * format. If the buffer would overflow, it is reallocated and grown
+ * as appropriate. Special cases of converting internal form of values
+ * to those used by "share" are done. this function does one property
+ * at a time.
+ */
+
+static void
+nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
+			sa_property_t prop, int sep)
+{
+	char *name;
+	char *value;
+	int curlen;
+	char *buff = *rbuff;
+	size_t buffsize = *rbuffsize;
+
+	name = sa_get_property_attr(prop, "type");
+	value = sa_get_property_attr(prop, "value");
+	if (buff != NULL)
+	    curlen = strlen(buff);
+	else
+	    curlen = 0;
+	if (name != NULL) {
+	    int len;
+	    len = strlen(name) + sep;
+
+		/*
+		 * A future RFE would be to replace this with more
+		 * generic code and to possibly handle more types.
+		 */
+	    switch (gettype(name)) {
+	    case OPT_TYPE_BOOLEAN:
+		if (value != NULL && strcasecmp(value, "false") == 0) {
+		    *name = '\0';
+		}
+		if (value != NULL)
+		    sa_free_attr_string(value);
+		value = NULL;
+		break;
+	    case OPT_TYPE_ACCLIST:
+		if (value != NULL && strcmp(value, "*") == 0) {
+		    sa_free_attr_string(value);
+		    value = NULL;
+		} else {
+		    if (value != NULL)
+			len += 1 + strlen(value);
+		}
+		break;
+	    case OPT_TYPE_LOGTAG:
+		if (value != NULL && strlen(value) == 0) {
+		    sa_free_attr_string(value);
+		    value = NULL;
+		} else {
+		    if (value != NULL)
+			len += 1 + strlen(value);
+		}
+		break;
+	    default:
+		if (value != NULL)
+		    len += 1 + strlen(value);
+		break;
+	    }
+	    while (buffsize <= (curlen + len)) {
+		/* need more room */
+		buffsize += incr;
+		buff = realloc(buff, buffsize);
+		if (buff == NULL) {
+		    /* realloc failed so free everything */
+		    if (*rbuff != NULL)
+			free(*rbuff);
+		}
+		*rbuff = buff;
+		*rbuffsize = buffsize;
+		if (buff == NULL) {
+		    return;
+		}
+	    }
+	    if (buff == NULL)
+		return;
+	    if (value == NULL)
+		(void) snprintf(buff + curlen, buffsize - curlen,
+				"%s%s", sep ? "," : "",
+				name, value != NULL ? value : "");
+	    else
+		(void) snprintf(buff + curlen, buffsize - curlen,
+				"%s%s=%s", sep ? "," : "",
+				name, value != NULL ? value : "");
+	}
+	if (name != NULL)
+	    sa_free_attr_string(name);
+	if (value != NULL)
+	    sa_free_attr_string(value);
+}
+
+/*
+ * nfs_format_options(group, hier)
+ *
+ * format all the options on the group into an old-style option
+ * string. If hier is non-zero, walk up the tree to get inherited
+ * options.
+ */
+
+static char *
+nfs_format_options(sa_group_t group, int hier)
+{
+	sa_optionset_t options = NULL;
+	sa_optionset_t secoptions;
+	sa_property_t prop, secprop;
+	sa_security_t security;
+	char *buff;
+	size_t buffsize;
+
+	options = sa_get_derived_optionset(group, "nfs", hier);
+
+	/*
+	 * have a an optionset relative to this item, if any. format
+	 * these then add any security definitions.
+	 */
+	buff = malloc(OPT_CHUNK);
+	if (buff != NULL) {
+	    int sep = 0;
+	    buff[0] = '\0';
+	    buffsize = OPT_CHUNK;
+		/*
+		 * do the default set first but skip any option that is also
+		 * in the protocol specific optionset.
+		 */
+	    if (options != NULL) {
+		for (prop = sa_get_property(options, NULL); prop != NULL;
+			prop = sa_get_next_property(prop)) {
+			/*
+			 * use this one since we skipped any of these that
+			 * were also in optdefault
+			 */
+		    nfs_sprint_option(&buff, &buffsize, OPT_CHUNK, prop, sep);
+		    if (buff == NULL) {
+			/*
+			 * buff could become NULL if there isn't
+			 * enough memory for nfs_sprint_option to
+			 * realloc() as necessary. We can't really do
+			 * anything about it at this point so we
+			 * return NULL.  The caller should handle the
+			 * failure. Note that this
+			 */
+			return (buff);
+		    }
+		    sep = 1;
+		}
+	    }
+	    secoptions = (sa_optionset_t)sa_get_all_security_types(group,
+								"nfs", hier);
+	    if (secoptions != NULL) {
+		for (secprop = sa_get_property(secoptions, NULL);
+		    secprop != NULL; secprop = sa_get_next_property(secprop)) {
+		    char *sectype;
+
+		    sectype = sa_get_property_attr(secprop, "type");
+		    security = (sa_security_t)sa_get_derived_security(group,
+								sectype,
+								"nfs", hier);
+		    if (security != NULL) {
+			if (sectype != NULL) {
+			    prop = sa_create_property("sec", sectype);
+			    nfs_sprint_option(&buff, &buffsize, OPT_CHUNK,
+						prop, sep);
+			    (void) sa_remove_property(prop);
+			sep = 1;
+			}
+			for (prop = sa_get_property(security, NULL);
+			    prop != NULL;
+			    prop = sa_get_next_property(prop)) {
+
+			    nfs_sprint_option(&buff, &buffsize, OPT_CHUNK,
+						prop, sep);
+			    if (buff == NULL) {
+				/* catastrophic memory failure */
+				sa_free_derived_optionset(secoptions);
+				if (security != NULL)
+				    sa_free_derived_optionset(security);
+				if (sectype != NULL)
+				    sa_free_attr_string(sectype);
+				if (options != NULL)
+				    sa_free_derived_optionset(options);
+				return (buff);
+			    }
+			    sep = 1;
+			}
+			sa_free_derived_optionset(security);
+		    }
+		    if (sectype != NULL)
+			sa_free_attr_string(sectype);
+		}
+		sa_free_derived_optionset(secoptions);
+	    }
+	}
+	if (options != NULL)
+	    sa_free_derived_optionset(options);
+	return (buff);
+}
+/*
+ * Append an entry to the nfslogtab file
+ */
+static int
+nfslogtab_add(dir, buffer, tag)
+	char *dir, *buffer, *tag;
+{
+	FILE *f;
+	struct logtab_ent lep;
+	int error = 0;
+
+	/*
+	 * Open the file for update and create it if necessary.
+	 * This may leave the I/O offset at the end of the file,
+	 * so rewind back to the beginning of the file.
+	 */
+	f = fopen(NFSLOGTAB, "a+");
+	if (f == NULL) {
+		error = errno;
+		goto out;
+	}
+	rewind(f);
+
+	if (lockf(fileno(f), F_LOCK, 0L) < 0) {
+		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			"share complete, however failed to lock %s "
+			"for update: %s\n"), NFSLOGTAB, strerror(errno));
+		error = -1;
+		goto out;
+	}
+
+	if (logtab_deactivate_after_boot(f) == -1) {
+		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			"share complete, however could not deactivate "
+			"entries in %s\n"), NFSLOGTAB);
+		error = -1;
+		goto out;
+	}
+
+	/*
+	 * Remove entries matching buffer and sharepoint since we're
+	 * going to replace it with perhaps an entry with a new tag.
+	 */
+	if (logtab_rement(f, buffer, dir, NULL, -1)) {
+		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			"share complete, however could not remove matching "
+			"entries in %s\n"), NFSLOGTAB);
+		error = -1;
+		goto out;
+	}
+
+	/*
+	 * Deactivate all active entries matching this sharepoint
+	 */
+	if (logtab_deactivate(f, NULL, dir, NULL)) {
+		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			"share complete, however could not deactivate matching "
+			"entries in %s\n"), NFSLOGTAB);
+		error = -1;
+		goto out;
+	}
+
+	lep.le_buffer = buffer;
+	lep.le_path = dir;
+	lep.le_tag = tag;
+	lep.le_state = LES_ACTIVE;
+
+	/*
+	 * Add new sharepoint / buffer location to nfslogtab
+	 */
+	if (logtab_putent(f, &lep) < 0) {
+		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			"share complete, however could not add %s to %s\n"),
+			dir, NFSLOGTAB);
+		error = -1;
+	}
+
+out:
+	if (f != NULL)
+		(void) fclose(f);
+	return (error);
+}
+
+/*
+ * Deactivate an entry from the nfslogtab file
+ */
+static int
+nfslogtab_deactivate(path)
+	char *path;
+{
+	FILE *f;
+	int error = 0;
+
+	f = fopen(NFSLOGTAB, "r+");
+	if (f == NULL) {
+		error = errno;
+		goto out;
+	}
+	if (lockf(fileno(f), F_LOCK, 0L) < 0) {
+		error = errno;
+		(void)  fprintf(stderr, dgettext(TEXT_DOMAIN,
+			"share complete, however could not lock %s for "
+			"update: %s\n"), NFSLOGTAB, strerror(error));
+		goto out;
+	}
+	if (logtab_deactivate(f, NULL, path, NULL) == -1) {
+		error = -1;
+		(void) fprintf(stderr,
+			dgettext(TEXT_DOMAIN,
+				"share complete, however could not "
+				"deactivate %s in %s\n"), path, NFSLOGTAB);
+		goto out;
+	}
+
+out:	if (f != NULL)
+		(void) fclose(f);
+
+	return (error);
+}
+
+/*
+ * public_exists(share)
+ *
+ * check to see if public option is set on any other share than the
+ * one specified.
+ */
+static int
+public_exists(sa_share_t skipshare)
+{
+	sa_share_t share;
+	sa_group_t group;
+	sa_optionset_t opt;
+	sa_property_t prop;
+	int exists = 0;
+	sa_handle_t handle;
+
+	group = sa_get_parent_group(skipshare);
+	if (group == NULL)
+	    return (SA_NO_SUCH_GROUP);
+
+	handle = sa_find_group_handle(group);
+	if (handle == NULL)
+	    return (SA_SYSTEM_ERR);
+
+	for (group = sa_get_group(handle, NULL); group != NULL;
+	    group = sa_get_next_group(group)) {
+	    for (share = sa_get_share(group, NULL); share != NULL;
+		share = sa_get_next_share(share)) {
+		if (share == skipshare)
+		    continue;
+		opt = sa_get_optionset(share, "nfs");
+		if (opt != NULL) {
+		    prop = sa_get_property(opt, "public");
+		    if (prop != NULL) {
+			char *shared;
+			shared = sa_get_share_attr(share, "shared");
+			if (shared != NULL) {
+			    exists = strcmp(shared, "true") == 0;
+			    sa_free_attr_string(shared);
+			    goto out;
+			}
+		    }
+		}
+	    }
+	}
+out:
+	return (exists);
+}
+
+/*
+ * sa_enable_share at the protocol level, enable_share must tell the
+ * implementation that it is to enable the share. This entails
+ * converting the path and options into the appropriate ioctl
+ * calls. It is assumed that all error checking of paths, etc. were
+ * done earlier.
+ */
+static int
+nfs_enable_share(sa_share_t share)
+{
+	struct exportdata export;
+	sa_optionset_t secoptlist;
+	struct secinfo *sp;
+	int num_secinfo;
+	sa_optionset_t opt;
+	sa_security_t sec;
+	sa_property_t prop;
+	char *path;
+	int err = SA_OK;
+
+	/* Don't drop core if the NFS module isn't loaded. */
+	(void) signal(SIGSYS, SIG_IGN);
+
+	/* get the path since it is important in several places */
+	path = sa_get_share_attr(share, "path");
+	if (path == NULL)
+	    return (SA_NO_SUCH_PATH);
+
+	/*
+	 * find the optionsets and security sets.  There may not be
+	 * any or there could be one or two for each of optionset and
+	 * security may have multiple, one per security type per
+	 * protocol type.
+	 */
+	opt = sa_get_derived_optionset(share, "nfs", 1);
+	secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1);
+	if (secoptlist != NULL)
+	    num_secinfo = MAX(1, count_security(secoptlist));
+	else
+	    num_secinfo = 1;
+
+	/*
+	 * walk through the options and fill in the structure
+	 * appropriately.
+	 */
+
+	(void) memset(&export, '\0', sizeof (export));
+
+	/*
+	 * do non-security options first since there is only one after
+	 * the derived group is constructed.
+	 */
+	export.ex_version = EX_CURRENT_VERSION;
+	export.ex_anon = UID_NOBODY; /* this is our default value */
+	export.ex_index = NULL;
+	export.ex_path = path;
+	export.ex_pathlen = strlen(path) + 1;
+
+	sp = calloc(num_secinfo, sizeof (struct secinfo));
+
+	if (opt != NULL)
+	    err = fill_export_from_optionset(&export, opt);
+
+	/*
+	 * check to see if "public" is set. If it is, then make sure
+	 * no other share has it set. If it is already used, fail.
+	 */
+
+	if (export.ex_flags & EX_PUBLIC && public_exists(share)) {
+	    (void) printf(dgettext(TEXT_DOMAIN,
+					"NFS: Cannot share more than one file "
+			    "system with 'public' property\n"));
+	    err = SA_NOT_ALLOWED;
+	    goto out;
+	}
+
+	if (sp == NULL) {
+		/* failed to alloc memory */
+	    (void) printf("NFS: no memory for security\n");
+	    err = SA_NO_MEMORY;
+	} else {
+	    int i;
+	    export.ex_secinfo = sp;
+	    /* get default secinfo */
+	    export.ex_seccnt = num_secinfo;
+		/*
+		 * since we must have one security option defined, we
+		 * init to the default and then override as we find
+		 * defined security options. This handles the case
+		 * where we have no defined options but we need to set
+		 * up one.
+		 */
+	    sp[0].s_window = DEF_WIN;
+	    sp[0].s_rootnames = NULL;
+	    /* setup a default in case no properties defined */
+	    if (nfs_getseconfig_default(&sp[0].s_secinfo)) {
+		(void) printf(dgettext(TEXT_DOMAIN,
+				    "NFS: nfs_getseconfig_default: failed to "
+				    "get default security mode\n"));
+		err = SA_CONFIG_ERR;
+	    }
+	    if (secoptlist != NULL) {
+		for (i = 0, prop = sa_get_property(secoptlist, NULL);
+		    prop != NULL && i < num_secinfo;
+		    prop = sa_get_next_property(prop), i++) {
+		    char *sectype;
+
+		    sectype = sa_get_property_attr(prop, "type");
+		    /* if sectype is NULL, we can't do anything so skip */
+		    if (sectype == NULL)
+			continue;
+		    sec = (sa_security_t)sa_get_derived_security(share,
+								sectype,
+								"nfs", 1);
+		    sp[i].s_window = DEF_WIN;
+		    sp[i].s_rootcnt = 0;
+		    sp[i].s_rootnames = NULL;
+
+		    (void) fill_security_from_secopts(&sp[i], sec);
+		    if (sec != NULL)
+			sa_free_derived_security(sec);
+		    if (sectype != NULL)
+			sa_free_attr_string(sectype);
+		}
+	    }
+		/*
+		 * when we get here, we can do the exportfs system call and
+		 * initiate thinsg. We probably want to enable the nfs.server
+		 * service first if it isn't running within SMF.
+		 */
+		/* check nfs.server status and start if needed */
+
+		/* now add the share to the internal tables */
+	    printarg(path, &export);
+		/*
+		 * call the exportfs system call which is implemented
+		 * via the nfssys() call as the EXPORTFS subfunction.
+		 */
+	    if ((err = exportfs(path, &export)) < 0) {
+		err = SA_SYSTEM_ERR;
+		switch (errno) {
+		case EREMOTE:
+		    (void) printf(dgettext(TEXT_DOMAIN,
+						"NFS: Cannot share remote file"
+						"system: %s\n"),
+					path);
+		    break;
+		case EPERM:
+		    if (getzoneid() != GLOBAL_ZONEID) {
+			(void) printf(dgettext(TEXT_DOMAIN,
+					"NFS: Cannot share file systems "
+					"in non-global zones: %s\n"), path);
+			err = SA_NOT_SUPPORTED;
+			break;
+		    }
+		    err = SA_NO_PERMISSION;
+		    /* FALLTHROUGH */
+		default:
+		    break;
+		}
+	    } else {
+		/* update sharetab with an add/modify */
+		(void) sa_update_sharetab(share, "nfs");
+	    }
+	}
+
+	if (err == SA_OK) {
+		/*
+		 * enable services as needed. This should probably be
+		 * done elsewhere in order to minimize the calls to
+		 * check services.
+		 */
+		/*
+		 * check to see if logging and other services need to
+		 * be triggered, but only if there wasn't an
+		 * error. This is probably where sharetab should be
+		 * updated with the NFS specific entry.
+		 */
+	    if (export.ex_flags & EX_LOG) {
+		/* enable logging */
+		if (nfslogtab_add(path, export.ex_log_buffer,
+		    export.ex_tag) != 0) {
+		    (void) fprintf(stderr,
+				dgettext(TEXT_DOMAIN,
+					"Could not enable logging for %s\n"),
+				path);
+		}
+		_check_services(service_list_logging);
+	    } else {
+		/*
+		 * don't have logging so remove it from file. It might
+		 * not be thre, but that doesn't matter.
+		 */
+		(void) nfslogtab_deactivate(path);
+		_check_services(service_list_default);
+	    }
+	}
+
+out:
+	if (path != NULL)
+	    free(path);
+
+	cleanup_export(&export);
+	if (opt != NULL)
+	    sa_free_derived_optionset(opt);
+	if (secoptlist != NULL)
+	    (void) sa_destroy_optionset(secoptlist);
+	return (err);
+}
+
+/*
+ * nfs_disable_share(share)
+ *
+ * Unshare the specified share.  How much error checking should be
+ * done? We only do basic errors for now.
+ */
+static int
+nfs_disable_share(char *share)
+{
+	int err;
+	int ret = SA_OK;
+
+	if (share != NULL) {
+	    err = exportfs(share, NULL);
+	    if (err < 0) {
+		/* TBD: only an error in some cases - need better analysis */
+		switch (errno) {
+		case EPERM:
+		case EACCES:
+		    ret = SA_NO_PERMISSION;
+		    if (getzoneid() != GLOBAL_ZONEID) {
+			ret = SA_NOT_SUPPORTED;
+		    }
+		    break;
+		case EINVAL:
+		case ENOENT:
+		    ret = SA_NO_SUCH_PATH;
+		    break;
+		default:
+		    ret = SA_SYSTEM_ERR;
+		    break;
+		}
+	    }
+	    if (ret == SA_OK || ret == SA_NO_SUCH_PATH) {
+		(void) sa_delete_sharetab(share, "nfs");
+		/* just in case it was logged */
+		(void) nfslogtab_deactivate(share);
+	    }
+	}
+	return (ret);
+}
+
+/*
+ * check ro vs rw values.  Over time this may get beefed up.
+ * for now it just does simple checks.
+ */
+
+static int
+check_rorw(char *v1, char *v2)
+{
+	int ret = SA_OK;
+	if (strcmp(v1, v2) == 0)
+	    ret = SA_VALUE_CONFLICT;
+	return (ret);
+}
+
+/*
+ * nfs_validate_property(property, parent)
+ *
+ * Check that the property has a legitimate value for its type.
+ */
+
+static int
+nfs_validate_property(sa_property_t property, sa_optionset_t parent)
+{
+	int ret = SA_OK;
+	char *propname;
+	char *other;
+	int optindex;
+	nfsl_config_t *configlist;
+	sa_group_t parent_group;
+	char *value;
+
+	propname = sa_get_property_attr(property, "type");
+
+	if ((optindex = findopt(propname)) < 0)
+	    ret = SA_NO_SUCH_PROP;
+
+	/* need to validate value range here as well */
+
+	if (ret == SA_OK) {
+	    parent_group = sa_get_parent_group((sa_share_t)parent);
+	    if (optdefs[optindex].share && !sa_is_share(parent_group)) {
+		ret = SA_PROP_SHARE_ONLY;
+	    }
+	}
+	if (ret == SA_OK) {
+	    value = sa_get_property_attr(property, "value");
+	    if (value != NULL) {
+		/* first basic type checking */
+		switch (optdefs[optindex].type) {
+		case OPT_TYPE_NUMBER:
+		    /* check that the value is all digits */
+		    if (!is_a_number(value))
+			ret = SA_BAD_VALUE;
+		    break;
+		case OPT_TYPE_BOOLEAN:
+		    if (strlen(value) == 0 ||
+			strcasecmp(value, "true") == 0 ||
+			strcmp(value, "1") == 0 ||
+			strcasecmp(value, "false") == 0 ||
+			strcmp(value, "0") == 0) {
+			ret = SA_OK;
+		    } else {
+			ret = SA_BAD_VALUE;
+		    }
+		    break;
+		case OPT_TYPE_USER:
+		    if (!is_a_number(value)) {
+			struct passwd *pw;
+			/* in this case it would have to be a user name */
+			pw = getpwnam(value);
+			if (pw == NULL)
+			    ret = SA_BAD_VALUE;
+			endpwent();
+		    } else {
+			uint64_t intval;
+			intval = strtoull(value, NULL, 0);
+			if (intval > UID_MAX && intval != ~0)
+			    ret = SA_BAD_VALUE;
+		    }
+		    break;
+		case OPT_TYPE_FILE:
+		    if (strcmp(value, "..") == 0 ||
+			strchr(value, '/') != NULL) {
+			ret = SA_BAD_VALUE;
+		    }
+		    break;
+		case OPT_TYPE_ACCLIST:
+			/*
+			 * access list handling. Should eventually
+			 * validate that all the values make sense.
+			 * Also, ro and rw may have cross value
+			 * conflicts.
+			 */
+		    if (strcmp(propname, SHOPT_RO) == 0)
+			other = SHOPT_RW;
+		    else if (strcmp(propname, SHOPT_RW) == 0)
+			other = SHOPT_RO;
+		    else
+			other = NULL;
+		    if (other != NULL && parent != NULL) {
+			/* compare rw(ro) with ro(rw) */
+			sa_property_t oprop;
+			oprop = sa_get_property(parent, other);
+			if (oprop != NULL) {
+			    /* only potential confusion if other exists */
+			    char *ovalue;
+			    ovalue = sa_get_property_attr(oprop, "value");
+			    if (ovalue != NULL) {
+				ret = check_rorw(value, ovalue);
+				sa_free_attr_string(ovalue);
+			    }
+			}
+		    }
+		    break;
+		case OPT_TYPE_LOGTAG:
+		    if (nfsl_getconfig_list(&configlist) == 0) {
+			int error;
+			if (value == NULL || strlen(value) == 0) {
+			    if (value != NULL)
+				sa_free_attr_string(value);
+			    value = strdup("global");
+			}
+			if (nfsl_findconfig(configlist, value, &error) == NULL)
+			    ret = SA_BAD_VALUE;
+			nfsl_freeconfig_list(&configlist);
+		    } else {
+			ret = SA_CONFIG_ERR;
+		    }
+		    break;
+		case OPT_TYPE_STRING:
+		    /* whatever is here should be ok */
+		    break;
+		case OPT_TYPE_SECURITY:
+			/*
+			 * The "sec" property isn't used in the
+			 * non-legacy parts of sharemgr. We need to
+			 * reject it here. For legacy, it is pulled
+			 * out well before we get here.
+			 */
+		    ret = SA_NO_SUCH_PROP;
+		    break;
+		default:
+		    break;
+		}
+		sa_free_attr_string(value);
+		if (ret == SA_OK && optdefs[optindex].check != NULL) {
+		    /* do the property specific check */
+		    ret = optdefs[optindex].check(property);
+		}
+	    }
+	}
+
+	if (propname != NULL)
+	    sa_free_attr_string(propname);
+	return (ret);
+}
+
+/*
+ * Protocol management functions
+ *
+ * Properties defined in the default files are defined in
+ * proto_option_defs for parsing and validation. If "other" and
+ * "compare" are set, then the value for this property should be
+ * compared against the property specified in "other" using the
+ * "compare" check (either <= or >=) in order to ensure that the
+ * values are in the correct range.  E.g. setting server_versmin
+ * higher than server_versmax should not be allowed.
+ */
+
+struct proto_option_defs {
+	char *tag;
+	char *name;	/* display name -- remove protocol identifier */
+	int index;
+	int type;
+	union {
+	    int intval;
+	    char *string;
+	} defvalue;
+	uint32_t svcs;
+	int32_t minval;
+	int32_t maxval;
+	char *file;
+	char *other;
+	int compare;
+#define	OPT_CMP_GE	0
+#define	OPT_CMP_LE	1
+	int (*check)(char *);
+} proto_options[] = {
+#define	PROTO_OPT_NFSD_SERVERS			0
+	{"nfsd_servers",
+	    "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 16, SVC_NFSD,
+	    1, INT32_MAX, NFSADMIN},
+#define	PROTO_OPT_LOCKD_LISTEN_BACKLOG		1
+	{"lockd_listen_backlog",
+	    "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG,
+	    OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX, NFSADMIN},
+#define	PROTO_OPT_LOCKD_SERVERS			2
+	{"lockd_servers",
+	    "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 20,
+	    SVC_LOCKD, 1, INT32_MAX, NFSADMIN},
+#define	PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT	3
+	{"lockd_retransmit_timeout",
+	    "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT,
+	    OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX, NFSADMIN},
+#define	PROTO_OPT_GRACE_PERIOD			4
+	{"grace_period",
+	    "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90,
+	    SVC_LOCKD, 0, INT32_MAX, NFSADMIN},
+#define	PROTO_OPT_NFS_SERVER_VERSMIN		5
+	{"nfs_server_versmin",
+	    "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER,
+	    (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
+	    NFS_VERSMAX, NFSADMIN, "server_versmax", OPT_CMP_LE},
+#define	PROTO_OPT_NFS_SERVER_VERSMAX		6
+	{"nfs_server_versmax",
+	    "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER,
+	    (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
+	    NFS_VERSMAX, NFSADMIN, "server_versmin", OPT_CMP_GE},
+#define	PROTO_OPT_NFS_CLIENT_VERSMIN		7
+	{"nfs_client_versmin",
+	    "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER,
+	    (int)NFS_VERSMIN_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX,
+	    NFSADMIN, "client_versmax", OPT_CMP_LE},
+#define	PROTO_OPT_NFS_CLIENT_VERSMAX		8
+	{"nfs_client_versmax",
+	    "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER,
+	    (int)NFS_VERSMAX_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX,
+	    NFSADMIN, "client_versmin", OPT_CMP_GE},
+#define	PROTO_OPT_NFS_SERVER_DELEGATION		9
+	{"nfs_server_delegation",
+	    "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION,
+	    OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0,
+	    NFSADMIN},
+#define	PROTO_OPT_NFSMAPID_DOMAIN		10
+	{"nfsmapid_domain",
+	    "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN,
+	    NULL, SVC_NFSMAPID, 0, 0, NFSADMIN},
+#define	PROTO_OPT_NFSD_MAX_CONNECTIONS		11
+	{"nfsd_max_connections",
+	    "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS,
+	    OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX, NFSADMIN},
+#define	PROTO_OPT_NFSD_PROTOCOL			12
+	{"nfsd_protocol",
+	    "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0,
+	    SVC_NFSD, 0, 0, NFSADMIN},
+#define	PROTO_OPT_NFSD_LISTEN_BACKLOG		13
+	{"nfsd_listen_backlog",
+	    "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG,
+	    OPT_TYPE_NUMBER, 0,
+	    SVC_LOCKD, 0, INT32_MAX, NFSADMIN},
+	{NULL}
+};
+
+/*
+ * the protoset holds the defined options so we don't have to read
+ * them multiple times
+ */
+sa_protocol_properties_t protoset;
+
+static int
+findprotoopt(char *name, int whichname)
+{
+	int i;
+	for (i = 0; proto_options[i].tag != NULL; i++) {
+	    if (whichname == 1) {
+		if (strcasecmp(proto_options[i].name, name) == 0)
+			return (i);
+	    } else {
+		if (strcasecmp(proto_options[i].tag, name) == 0)
+			return (i);
+	    }
+	}
+	return (-1);
+}
+
+/*
+ * fixcaselower(str)
+ *
+ * convert a string to lower case (inplace).
+ */
+
+static void
+fixcaselower(char *str)
+{
+	while (*str) {
+	    *str = tolower(*str);
+	    str++;
+	}
+}
+
+/*
+ * fixcaseupper(str)
+ *
+ * convert a string to upper case (inplace).
+ */
+
+static void
+fixcaseupper(char *str)
+{
+	while (*str) {
+	    *str = toupper(*str);
+	    str++;
+	}
+}
+
+/*
+ * initprotofromdefault()
+ *
+ * read the default file(s) and add the defined values to the
+ * protoset.  Note that default values are known from the built in
+ * table in case the file doesn't have a definition.
+ */
+
+static int
+initprotofromdefault()
+{
+	FILE *nfs;
+	char buff[BUFSIZ];
+	char *name;
+	char *value;
+	sa_property_t prop;
+	int index;
+
+	protoset = sa_create_protocol_properties("nfs");
+
+	if (protoset != NULL) {
+	    nfs = fopen(NFSADMIN, "r");
+	    if (nfs != NULL) {
+		while (fgets(buff, sizeof (buff), nfs) != NULL) {
+		    switch (buff[0]) {
+		    case '\n':
+		    case '#':
+			/* skip */
+			break;
+		    default:
+			name = buff;
+			buff[strlen(buff) - 1] = '\0';
+			value = strchr(name, '=');
+			if (value != NULL) {
+			    *value++ = '\0';
+			    if ((index = findprotoopt(name, 0)) >= 0) {
+				fixcaselower(name);
+				prop = sa_create_property(
+					proto_options[index].name,
+					value);
+				(void) sa_add_protocol_property(protoset, prop);
+			    }
+			}
+		    }
+		}
+		if (nfs != NULL)
+		    (void) fclose(nfs);
+	    }
+	}
+	if (protoset == NULL)
+	    return (SA_NO_MEMORY);
+	return (SA_OK);
+}
+
+/*
+ * add_default()
+ *
+ * Add the default values for any property not defined in the parsing
+ * of the default files. Values are set according to their defined
+ * types.
+ */
+
+static void
+add_defaults()
+{
+	int i;
+	char number[MAXDIGITS];
+
+	for (i = 0; proto_options[i].tag != NULL; i++) {
+	    sa_property_t prop;
+	    prop = sa_get_protocol_property(protoset, proto_options[i].name);
+	    if (prop == NULL) {
+		/* add the default value */
+		switch (proto_options[i].type) {
+		case OPT_TYPE_NUMBER:
+		    (void) snprintf(number, sizeof (number), "%d",
+				proto_options[i].defvalue.intval);
+		    prop = sa_create_property(proto_options[i].name, number);
+		    break;
+
+		case OPT_TYPE_BOOLEAN:
+		    prop = sa_create_property(proto_options[i].name,
+					proto_options[i].defvalue.intval ?
+					"true" : "false");
+		    break;
+
+		case OPT_TYPE_ONOFF:
+		    prop = sa_create_property(proto_options[i].name,
+					proto_options[i].defvalue.intval ?
+					"on" : "off");
+		    break;
+
+		default:
+		    /* treat as strings of zero length */
+		    prop = sa_create_property(proto_options[i].name, "");
+		    break;
+		}
+		if (prop != NULL)
+		    (void) sa_add_protocol_property(protoset, prop);
+	    }
+	}
+}
+
+static void
+free_protoprops()
+{
+	xmlFreeNode(protoset);
+}
+
+/*
+ * nfs_init()
+ *
+ * Initialize the NFS plugin.
+ */
+
+static int
+nfs_init()
+{
+	int ret = SA_OK;
+
+	if (sa_plugin_ops.sa_init != nfs_init)
+	    (void) printf(dgettext(TEXT_DOMAIN,
+				    "NFS plugin not properly initialized\n"));
+
+	ret = initprotofromdefault();
+	add_defaults();
+
+	return (ret);
+}
+
+/*
+ * nfs_fini()
+ *
+ * uninitialize the NFS plugin. Want to avoid memory leaks.
+ */
+
+static void
+nfs_fini()
+{
+	free_protoprops();
+}
+
+/*
+ * nfs_get_proto_set()
+ *
+ * Return an optionset with all the protocol specific properties in
+ * it.
+ */
+
+static sa_protocol_properties_t
+nfs_get_proto_set()
+{
+	return (protoset);
+}
+
+struct deffile {
+	struct deffile *next;
+	char *line;
+};
+
+/*
+ * read_default_file(fname)
+ *
+ * Read the specified default file. We return a list of entries. This
+ * get used for adding or removing values.
+ */
+
+static struct deffile *
+read_default_file(char *fname)
+{
+	FILE *file;
+	struct deffile *defs = NULL;
+	struct deffile *newdef;
+	struct deffile *prevdef = NULL;
+	char buff[BUFSIZ * 2];
+
+	file = fopen(fname, "r");
+	if (file != NULL) {
+	    while (fgets(buff, sizeof (buff), file) != NULL) {
+		newdef = (struct deffile *)calloc(1, sizeof (struct deffile));
+		if (newdef != NULL) {
+		    newdef->line = strdup(buff);
+		    if (defs == NULL) {
+			prevdef = defs = newdef;
+		    } else {
+			prevdef->next = newdef;
+			prevdef = newdef;
+		    }
+		}
+	    }
+	}
+	(void) fclose(file);
+	return (defs);
+}
+
+static void
+free_default_file(struct deffile *defs)
+{
+	struct deffile *curdefs = NULL;
+
+	while (defs != NULL) {
+	    curdefs = defs;
+	    defs = defs->next;
+	    if (curdefs->line != NULL)
+		free(curdefs->line);
+	    free(curdefs);
+	}
+}
+
+/*
+ * write_default_file(fname, defs)
+ *
+ * Write the default file back.
+ */
+
+static int
+write_default_file(char *fname, struct deffile *defs)
+{
+	FILE *file;
+	int ret = SA_OK;
+	sigset_t old, new;
+
+	file = fopen(fname, "w+");
+	if (file != NULL) {
+	    (void) sigprocmask(SIG_BLOCK, NULL, &new);
+	    (void) sigaddset(&new, SIGHUP);
+	    (void) sigaddset(&new, SIGINT);
+	    (void) sigaddset(&new, SIGQUIT);
+	    (void) sigaddset(&new, SIGTSTP);
+	    (void) sigprocmask(SIG_SETMASK, &new, &old);
+	    while (defs != NULL) {
+		(void) fputs(defs->line, file);
+		defs = defs->next;
+	    }
+	    (void) fsync(fileno(file));
+	    (void) sigprocmask(SIG_SETMASK, &old, NULL);
+	    (void) fclose(file);
+	} else {
+	    switch (errno) {
+	    case EPERM:
+	    case EACCES:
+		ret = SA_NO_PERMISSION;
+		break;
+	    default:
+		ret = SA_SYSTEM_ERR;
+	    }
+	}
+	return (ret);
+}
+
+
+/*
+ * set_default_file_value(tag, value)
+ *
+ * Set the default file value for tag to value. Then rewrite the file.
+ * tag and value are always set.  The caller must ensure this.
+ */
+
+#define	MAX_STRING_LENGTH	256
+static int
+set_default_file_value(char *tag, char *value)
+{
+	int ret = SA_OK;
+	struct deffile *root;
+	struct deffile *defs;
+	struct deffile *prev;
+	char string[MAX_STRING_LENGTH];
+	int len;
+	int update = 0;
+
+	(void) snprintf(string, MAX_STRING_LENGTH, "%s=", tag);
+	len = strlen(string);
+
+	root = defs = read_default_file(NFSADMIN);
+	if (root == NULL) {
+	    if (errno == EPERM || errno == EACCES)
+		ret = SA_NO_PERMISSION;
+	    else
+		ret = SA_SYSTEM_ERR;
+	} else {
+	    while (defs != NULL) {
+		if (defs->line != NULL &&
+		    strncasecmp(defs->line, string, len) == 0) {
+		    /* replace with the new value */
+		    free(defs->line);
+		    fixcaseupper(tag);
+		    (void) snprintf(string, sizeof (string), "%s=%s\n",
+					tag, value);
+		    string[MAX_STRING_LENGTH - 1] = '\0';
+		    defs->line = strdup(string);
+		    update = 1;
+		    break;
+		}
+		defs = defs->next;
+	    }
+	    if (!update) {
+		defs = root;
+		/* didn't find, so see if it is a comment */
+		(void) snprintf(string, MAX_STRING_LENGTH, "#%s=", tag);
+		len = strlen(string);
+		while (defs != NULL) {
+		    if (strncasecmp(defs->line, string, len) == 0) {
+			/* replace with the new value */
+			free(defs->line);
+			fixcaseupper(tag);
+			(void) snprintf(string, sizeof (string),
+				    "%s=%s\n", tag, value);
+			string[MAX_STRING_LENGTH - 1] = '\0';
+			defs->line = strdup(string);
+			update = 1;
+			break;
+		    }
+		    defs = defs->next;
+		}
+	    }
+	    if (!update) {
+		fixcaseupper(tag);
+		(void) snprintf(string, sizeof (string), "%s=%s\n",
+					tag, value);
+		prev = root;
+		while (prev->next != NULL)
+		    prev = prev->next;
+		defs = malloc(sizeof (struct deffile));
+		prev->next = defs;
+		if (defs != NULL) {
+		    defs->next = NULL;
+		    defs->line = strdup(string);
+		}
+	    }
+	    if (update) {
+		ret = write_default_file(NFSADMIN, root);
+	    }
+	    free_default_file(root);
+	}
+	return (ret);
+}
+
+/*
+ * service_in_state(service, chkstate)
+ *
+ * Want to know if the specified service is in the desired state
+ * (chkstate) or not. Return true (1) if it is and false (0) if it
+ * isn't.
+ */
+static int
+service_in_state(char *service, const char *chkstate)
+{
+	char *state;
+	int ret = B_FALSE;
+
+	state = smf_get_state(service);
+	if (state != NULL) {
+	    /* got the state so get the equality for the return value */
+	    ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
+	    free(state);
+	}
+	return (ret);
+}
+
+/*
+ * restart_service(svcs)
+ *
+ * Walk through the bit mask of services that need to be restarted in
+ * order to use the new property values. Some properties affect
+ * multiple daemons. Should only restart a service if it is currently
+ * enabled (online).
+ */
+
+static void
+restart_service(uint32_t svcs)
+{
+	uint32_t mask;
+	int ret;
+	char *service;
+
+	for (mask = 1; svcs != 0; mask <<= 1) {
+	    switch (svcs & mask) {
+	    case SVC_LOCKD:
+		service = LOCKD;
+		break;
+	    case SVC_STATD:
+		service = STATD;
+		break;
+	    case SVC_NFSD:
+		service = NFSD;
+		break;
+	    case SVC_MOUNTD:
+		service = MOUNTD;
+		break;
+	    case SVC_NFS4CBD:
+		service = NFS4CBD;
+		break;
+	    case SVC_NFSMAPID:
+		service = NFSMAPID;
+		break;
+	    case SVC_RQUOTAD:
+		service = RQUOTAD;
+		break;
+	    case SVC_NFSLOGD:
+		service = NFSLOGD;
+		break;
+	    default:
+		continue;
+	    }
+
+		/*
+		 * Only attempt to restart the service if it is
+		 * currently running. In the future, it may be
+		 * desirable to use smf_refresh_instance if the NFS
+		 * services ever implement the refresh method.
+		 */
+	    if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
+		ret = smf_restart_instance(service);
+		/*
+		 * There are only a few SMF errors at this point, but
+		 * it is also possible that a bad value may have put
+		 * the service into maintenance if there wasn't an
+		 * SMF level error.
+		 */
+		if (ret != 0) {
+		    (void) fprintf(stderr,
+				dgettext(TEXT_DOMAIN,
+					"%s failed to restart: %s\n"),
+				scf_strerror(scf_error()));
+		} else {
+			/*
+			 * Check whether it has gone to "maintenance"
+			 * mode or not. Maintenance implies something
+			 * went wrong.
+			 */
+		    if (service_in_state(service, SCF_STATE_STRING_MAINT)) {
+			(void) fprintf(stderr,
+					dgettext(TEXT_DOMAIN,
+						"%s failed to restart\n"),
+					service);
+		    }
+		}
+	    }
+	    svcs &= ~mask;
+	}
+}
+
+/*
+ * nfs_minmax_check(name, value)
+ *
+ * Verify that the value for the property specified by index is valid
+ * relative to the opposite value in the case of a min/max variable.
+ * Currently, server_minvers/server_maxvers and
+ * client_minvers/client_maxvers are the only ones to check.
+ */
+
+static int
+nfs_minmax_check(int index, int value)
+{
+	int val;
+	char *pval;
+	sa_property_t prop;
+	sa_optionset_t opts;
+	int ret = B_TRUE;
+
+	if (proto_options[index].other != NULL) {
+	    /* have a property to compare against */
+	    opts = nfs_get_proto_set();
+	    prop = sa_get_property(opts, proto_options[index].other);
+		/*
+		 * If we don't find the property, assume default
+		 * values which will work since the max will be at the
+		 * max and the min at the min.
+		 */
+	    if (prop != NULL) {
+		pval = sa_get_property_attr(prop, "value");
+		if (pval != NULL) {
+		    val = strtoul(pval, NULL, 0);
+		    if (proto_options[index].compare == OPT_CMP_LE) {
+			ret = value <= val ? B_TRUE : B_FALSE;
+		    } else if (proto_options[index].compare == OPT_CMP_GE) {
+			ret = value >= val ? B_TRUE : B_FALSE;
+		    }
+		}
+	    }
+	}
+	return (ret);
+}
+
+/*
+ * nfs_validate_proto_prop(index, name, value)
+ *
+ * Verify that the property specifed by name can take the new
+ * value. This is a sanity check to prevent bad values getting into
+ * the default files. All values need to be checked against what is
+ * allowed by their defined type. If a type isn't explicitly defined
+ * here, it is treated as a string.
+ *
+ * Note that OPT_TYPE_NUMBER will additionally check that the value is
+ * within the range specified and potentially against another property
+ * value as well as specified in the proto_options members other and
+ * compare.
+ */
+
+static int
+nfs_validate_proto_prop(int index, char *name, char *value)
+{
+	int ret = SA_OK;
+	char *cp;
+#ifdef lint
+	name = name;
+#endif
+
+	switch (proto_options[index].type) {
+	case OPT_TYPE_NUMBER:
+	    if (!is_a_number(value))
+		ret = SA_BAD_VALUE;
+	    else {
+		int val;
+		val = strtoul(value, NULL, 0);
+		if (val < proto_options[index].minval ||
+		    val > proto_options[index].maxval)
+		    ret = SA_BAD_VALUE;
+		/*
+		 * For server_versmin/server_versmax and
+		 * client_versmin/client_versmax, the value of the
+		 * min(max) should be checked to be correct relative
+		 * to the current max(min).
+		 */
+		if (!nfs_minmax_check(index, val)) {
+		    ret = SA_BAD_VALUE;
+		}
+	    }
+	    break;
+
+	case OPT_TYPE_DOMAIN:
+		/*
+		 * needs to be a qualified domain so will have at
+		 * least one period and other characters on either
+		 * side of it.  A zero length string is also allowed
+		 * and is the way to turn off the override.
+		 */
+	    if (strlen(value) == 0)
+		break;
+	    cp = strchr(value, '.');
+	    if (cp == NULL || cp == value || strchr(value, '@') != NULL)
+		ret = SA_BAD_VALUE;
+	    break;
+
+	case OPT_TYPE_BOOLEAN:
+	    if (strlen(value) == 0 ||
+		strcasecmp(value, "true") == 0 ||
+		strcmp(value, "1") == 0 ||
+		strcasecmp(value, "false") == 0 ||
+		strcmp(value, "0") == 0) {
+		ret = SA_OK;
+	    } else {
+		ret = SA_BAD_VALUE;
+	    }
+	    break;
+
+	case OPT_TYPE_ONOFF:
+	    if (strcasecmp(value, "on") != 0 &&
+		strcasecmp(value, "off") != 0) {
+		ret = SA_BAD_VALUE;
+	    }
+	    break;
+
+	case OPT_TYPE_PROTOCOL:
+	    if (strcasecmp(value, "all") != 0 &&
+		strcasecmp(value, "tcp") != 0 &&
+		strcasecmp(value, "udp") != 0)
+		ret = SA_BAD_VALUE;
+	    break;
+
+	default:
+	    /* treat as a string */
+	    break;
+	}
+	return (ret);
+}
+
+/*
+ * nfs_set_proto_prop(prop)
+ *
+ * check that prop is valid.
+ */
+
+static int
+nfs_set_proto_prop(sa_property_t prop)
+{
+	int ret = SA_OK;
+	char *name;
+	char *value;
+
+	name = sa_get_property_attr(prop, "type");
+	value = sa_get_property_attr(prop, "value");
+	if (name != NULL && value != NULL) {
+	    int index = findprotoopt(name, 1);
+	    if (index >= 0) {
+		/* should test for valid value */
+		ret = nfs_validate_proto_prop(index, name, value);
+		if (ret == SA_OK)
+		    ret = set_default_file_value(proto_options[index].tag,
+							value);
+		if (ret == SA_OK)
+		    restart_service(proto_options[index].svcs);
+	    }
+	}
+	if (name != NULL)
+	    sa_free_attr_string(name);
+	if (value != NULL)
+	    sa_free_attr_string(value);
+	return (ret);
+}
+
+/*
+ * nfs_get_status()
+ *
+ * What is the current status of the nfsd? We use the SMF state here.
+ * Caller must free the returned value.
+ */
+
+static char *
+nfs_get_status()
+{
+	char *state;
+	state = smf_get_state(NFSD);
+	return (state != NULL ? state : strdup("-"));
+}
+
+/*
+ * nfs_space_alias(alias)
+ *
+ * Lookup the space (security) name. If it is default, convert to the
+ * real name.
+ */
+
+static char *
+nfs_space_alias(char *space)
+{
+	char *name = space;
+	seconfig_t secconf;
+
+	/*
+	 * Only the space named "default" is special. If it is used,
+	 * the default needs to be looked up and the real name used.
+	 * This is normally "sys" but could be changed.  We always
+	 * change defautl to the real name.
+	 */
+	if (strcmp(space, "default") == 0 &&
+	    nfs_getseconfig_default(&secconf) == 0) {
+	    if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0)
+		name = secconf.sc_name;
+	}
+	return (strdup(name));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.h	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,131 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * basic API declarations for share management
+ */
+
+#ifndef _LIBSHARE_NFS_H
+#define	_LIBSHARE_NFS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* property names used by NFS */
+#define	SHOPT_RO	"ro"
+#define	SHOPT_RW	"rw"
+
+#define	SHOPT_SEC	"sec"
+#define	SHOPT_SECURE	"secure"
+#define	SHOPT_ROOT	"root"
+#define	SHOPT_ANON	"anon"
+#define	SHOPT_WINDOW	"window"
+#define	SHOPT_NOSUB	"nosub"
+#define	SHOPT_NOSUID	"nosuid"
+#define	SHOPT_ACLOK	"aclok"
+#define	SHOPT_PUBLIC	"public"
+#define	SHOPT_INDEX	"index"
+#define	SHOPT_LOG	"log"
+#define	SHOPT_CKSUM	"cksum"
+
+/*
+ * defined options types. These should be in a file rather than
+ * compiled in. Until there is a plugin mechanism to add new types,
+ * this is sufficient.
+ */
+#define	OPT_TYPE_ANY		0
+#define	OPT_TYPE_STRING		1
+#define	OPT_TYPE_BOOLEAN	2
+#define	OPT_TYPE_NUMBER		3
+#define	OPT_TYPE_RANGE		4
+#define	OPT_TYPE_USER		5
+#define	OPT_TYPE_ACCLIST	6
+#define	OPT_TYPE_DEPRECATED	7
+#define	OPT_TYPE_SECURITY	8
+#define	OPT_TYPE_PATH		9
+#define	OPT_TYPE_FILE		10
+#define	OPT_TYPE_LOGTAG		11
+#define	OPT_TYPE_STRINGSET	12
+#define	OPT_TYPE_DOMAIN		13
+#define	OPT_TYPE_ONOFF		14
+#define	OPT_TYPE_PROTOCOL	15
+
+#define	OPT_SHARE_ONLY		1
+
+struct option_defs {
+	char *tag;
+	int index;
+	int type;
+	int share;	/* share only option */
+	int (*check)(char *);
+};
+
+/*
+ * service bit mask values
+ */
+#define	SVC_LOCKD	0x0001
+#define	SVC_STATD	0x0002
+#define	SVC_NFSD	0x0004
+#define	SVC_MOUNTD	0x0008
+#define	SVC_NFS4CBD	0x0010
+#define	SVC_NFSMAPID	0x0020
+#define	SVC_RQUOTAD	0x0040
+#define	SVC_NFSLOGD	0x0080
+
+/*
+ * place holder for future service -- will move to daemon_utils.h when
+ * fully implemented.
+ */
+#define	NFSLOGD	"svc:/network/nfs/log:default"
+
+/* The NFS export structure flags for read/write modes */
+#define	NFS_RWMODES	(M_RO|M_ROL|M_RW|M_RWL)
+
+/* other values */
+/* max size of 64-bit integer in digits plus a bit extra */
+#define	MAXDIGITS	32
+
+/* external variable */
+extern boolean_t nfsl_errs_to_syslog;
+
+/* imported functions */
+extern int exportfs(char *, struct exportdata *);
+extern void _check_services(char **);
+extern int nfs_getseconfig_default(seconfig_t *);
+extern int nfs_getseconfig_byname(char *, seconfig_t *);
+extern bool_t nfs_get_root_principal(seconfig_t *, char *, caddr_t *);
+extern int nfsl_getconfig_list(nfsl_config_t **);
+extern void nfsl_freeconfig_list(nfsl_config_t **);
+extern nfsl_config_t *nfsl_findconfig(nfsl_config_t *, char *, int *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _LIBSHARE_NFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/mapfile-vers	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+SUNWprivate_1.1 {
+    global:
+	sa_plugin_ops;
+    local:
+	*;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/sparc/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/nfs/sparcv9/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/sparcv9/Makefile	Wed Mar 28 08:50:43 2007 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386	Wed Mar 28 08:50:43 2007 -0700
@@ -129,6 +129,7 @@
 s none usr/lib/amd64/llib-lsec.ln=../../../lib/amd64/llib-lsec.ln
 s none usr/lib/amd64/llib-lsecdb.ln=../../../lib/amd64/llib-lsecdb.ln
 s none usr/lib/amd64/llib-lsendfile.ln=../../../lib/amd64/llib-lsendfile.ln
+f none usr/lib/amd64/llib-lshare.ln 644 root bin
 f none usr/lib/amd64/llib-lsip.ln 644 root bin
 f none usr/lib/amd64/llib-lsldap.ln 644 root bin
 f none usr/lib/amd64/llib-lsmbios.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc	Wed Mar 28 08:50:43 2007 -0700
@@ -124,6 +124,7 @@
 s none usr/lib/sparcv9/llib-lsec.ln=../../../lib/sparcv9/llib-lsec.ln
 s none usr/lib/sparcv9/llib-lsecdb.ln=../../../lib/sparcv9/llib-lsecdb.ln
 s none usr/lib/sparcv9/llib-lsendfile.ln=../../../lib/sparcv9/llib-lsendfile.ln
+f none usr/lib/sparcv9/llib-lshare.ln 644 root bin
 f none usr/lib/sparcv9/llib-lsip.ln 644 root bin
 f none usr/lib/sparcv9/llib-lsldap.ln 644 root bin
 f none usr/lib/sparcv9/llib-lsmbios.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com	Wed Mar 28 08:50:43 2007 -0700
@@ -861,7 +861,6 @@
 f none usr/sbin/sharectl 555 root bin
 f none usr/sbin/sharemgr 555 root bin
 f none usr/lib/libshare.so.1 755 root bin
-s none usr/lib/libshare.so=./libshare.so.1
 l none usr/sbin/share=../../usr/sbin/sharemgr
 l none usr/sbin/unshare=../../usr/sbin/sharemgr
 f none usr/sbin/unshareall 555 root bin
--- a/usr/src/pkgdefs/SUNWcsu/prototype_i386	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_i386	Wed Mar 28 08:50:43 2007 -0700
@@ -144,6 +144,9 @@
 s none usr/lib/secure/64=amd64
 d none usr/lib/amd64 755 root bin
 s none usr/lib/amd64/ld.so.1=../../../lib/amd64/ld.so.1
+f none usr/lib/amd64/libshare.so.1 755 root bin
+d none usr/lib/fs/nfs 755 root sys
+d none usr/lib/fs/nfs/amd64 755 root sys
 d none usr/sbin/amd64 755 root bin
 f none usr/sbin/amd64/add_drv 555 root sys
 f none usr/sbin/amd64/modinfo 555 root sys
--- a/usr/src/pkgdefs/SUNWcsu/prototype_sparc	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_sparc	Wed Mar 28 08:50:43 2007 -0700
@@ -98,6 +98,9 @@
 s none usr/lib/secure/64=sparcv9
 d none usr/lib/sparcv9 755 root bin
 s none usr/lib/sparcv9/ld.so.1=../../../lib/sparcv9/ld.so.1
+f none usr/lib/sparcv9/libshare.so.1 755 root bin
+d none usr/lib/fs/nfs 755 root sys
+d none usr/lib/fs/nfs/sparcv9 755 root sys
 l none usr/sbin/prtdiag=../../usr/lib/platexec
 d none usr/sbin/sparcv9 755 root bin
 f none usr/sbin/sparcv9/add_drv 555 root sys
--- a/usr/src/pkgdefs/SUNWnfssu/prototype_com	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWnfssu/prototype_com	Wed Mar 28 08:50:43 2007 -0700
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -47,7 +47,7 @@
 d none usr/lib 755 root bin
 d none usr/lib/fs 755 root sys
 d none usr/lib/fs/nfs 755 root sys
-f none usr/lib/fs/nfs/libshare_nfs.so 555 root bin
+f none usr/lib/fs/nfs/libshare_nfs.so.1 755 root bin
 d none usr/lib/nfs 755 root sys
 f none usr/lib/nfs/mountd 555 root bin
 f none usr/lib/nfs/nfsd 555 root bin
--- a/usr/src/pkgdefs/SUNWnfssu/prototype_i386	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWnfssu/prototype_i386	Wed Mar 28 08:50:43 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,9 +18,8 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright (c) 2000 by Sun Microsystems, Inc.
-# All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
@@ -47,3 +45,5 @@
 #
 # SUNWnfssu
 #
+d none usr/lib/fs/nfs/amd64 755 root sys
+f none usr/lib/fs/nfs/amd64/libshare_nfs.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWnfssu/prototype_sparc	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/SUNWnfssu/prototype_sparc	Wed Mar 28 08:50:43 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,9 +18,8 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright (c) 2000 by Sun Microsystems, Inc.
-# All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
@@ -46,3 +44,5 @@
 #
 # SUNWnfssu
 #
+d none usr/lib/fs/nfs/sparcv9 755 root sys
+f none usr/lib/fs/nfs/sparcv9/libshare_nfs.so.1 755 root bin
--- a/usr/src/pkgdefs/etc/exception_list_i386	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Wed Mar 28 08:50:43 2007 -0700
@@ -816,3 +816,14 @@
 lib/llib-liscsitgt.ln			i386
 lib/amd64/libiscsitgt.so		i386
 lib/amd64/llib-liscsitgt.ln		i386
+#
+# libshare is private and the 64-bit sharemgr is not delivered.
+#
+usr/lib/libshare.so			i386
+usr/lib/amd64/libshare.so		i386
+usr/lib/fs/nfs/libshare_nfs.so		i386
+usr/lib/fs/nfs/amd64/libshare_nfs.so	i386
+usr/include/libshare_impl.h		i386
+usr/include/scfutil.h			i386
+usr/sbin/i86/sharemgr			i386
+usr/sbin/amd64/sharemgr			i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Wed Mar 28 07:55:32 2007 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Wed Mar 28 08:50:43 2007 -0700
@@ -885,6 +885,17 @@
 lib/sparcv9/libiscsitgt.so		sparc
 lib/sparcv9/llib-liscsitgt.ln		sparc
 #
+# libshare is private and the 64-bit sharemg is not delivered.
+#
+usr/lib/libshare.so			sparc
+usr/lib/sparcv9/libshare.so		sparc
+usr/lib/fs/nfs/libshare_nfs.so		sparc
+usr/lib/fs/nfs/sparcv9/libshare_nfs.so	sparc
+usr/include/libshare_impl.h		sparc
+usr/include/scfutil.h			sparc
+usr/sbin/sparcv9/sharemgr		sparc
+usr/sbin/sparcv7/sharemgr		sparc
+#
 # These files are installed in the proto area by the build of libpri for
 # the benefit of the builds of FMA libldom, Zeus, picld plugins, and/or
 # other libpri consumers. However, the libpri interfaces are private to