xref: /titanic_44/usr/src/lib/libshare/common/scfutil.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
16185db85Sdougm /*
26185db85Sdougm  * CDDL HEADER START
36185db85Sdougm  *
46185db85Sdougm  * The contents of this file are subject to the terms of the
56185db85Sdougm  * Common Development and Distribution License (the "License").
66185db85Sdougm  * You may not use this file except in compliance with the License.
76185db85Sdougm  *
86185db85Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96185db85Sdougm  * or http://www.opensolaris.org/os/licensing.
106185db85Sdougm  * See the License for the specific language governing permissions
116185db85Sdougm  * and limitations under the License.
126185db85Sdougm  *
136185db85Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
146185db85Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156185db85Sdougm  * If applicable, add the following below this CDDL HEADER, with the
166185db85Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
176185db85Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
186185db85Sdougm  *
196185db85Sdougm  * CDDL HEADER END
206185db85Sdougm  */
216185db85Sdougm 
226185db85Sdougm /*
23f345c0beSdougm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
246185db85Sdougm  * Use is subject to license terms.
256185db85Sdougm  */
266185db85Sdougm 
276185db85Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
286185db85Sdougm 
296185db85Sdougm /* helper functions for using libscf with sharemgr */
306185db85Sdougm 
316185db85Sdougm #include <libscf.h>
326185db85Sdougm #include <libxml/parser.h>
336185db85Sdougm #include <libxml/tree.h>
346185db85Sdougm #include "libshare.h"
356185db85Sdougm #include "libshare_impl.h"
366185db85Sdougm #include "scfutil.h"
376185db85Sdougm #include <string.h>
38*da6c28aaSamw #include <ctype.h>
396185db85Sdougm #include <errno.h>
406185db85Sdougm #include <uuid/uuid.h>
416185db85Sdougm #include <sys/param.h>
42f345c0beSdougm #include <signal.h>
436185db85Sdougm 
446185db85Sdougm ssize_t scf_max_name_len;
456185db85Sdougm extern struct sa_proto_plugin *sap_proto_list;
46549ec3ffSdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
476185db85Sdougm 
486185db85Sdougm /*
496185db85Sdougm  * The SMF facility uses some properties that must exist. We want to
506185db85Sdougm  * skip over these when processing protocol options.
516185db85Sdougm  */
526185db85Sdougm static char *skip_props[] = {
536185db85Sdougm 	"modify_authorization",
546185db85Sdougm 	"action_authorization",
556185db85Sdougm 	"value_authorization",
566185db85Sdougm 	NULL
576185db85Sdougm };
586185db85Sdougm 
596185db85Sdougm /*
606185db85Sdougm  * sa_scf_fini(handle)
616185db85Sdougm  *
6225a68471Sdougm  * Must be called when done. Called with the handle allocated in
636185db85Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
646185db85Sdougm  * still in use. Called by sa_fini().
656185db85Sdougm  */
666185db85Sdougm 
676185db85Sdougm void
686185db85Sdougm sa_scf_fini(scfutilhandle_t *handle)
696185db85Sdougm {
706185db85Sdougm 	if (handle != NULL) {
716185db85Sdougm 		int unbind = 0;
726185db85Sdougm 		if (handle->scope != NULL) {
736185db85Sdougm 			unbind = 1;
746185db85Sdougm 			scf_scope_destroy(handle->scope);
756185db85Sdougm 		}
76a3351425Sdougm 		if (handle->instance != NULL)
77a3351425Sdougm 			scf_instance_destroy(handle->instance);
786185db85Sdougm 		if (handle->service != NULL)
796185db85Sdougm 			scf_service_destroy(handle->service);
806185db85Sdougm 		if (handle->pg != NULL)
816185db85Sdougm 			scf_pg_destroy(handle->pg);
826185db85Sdougm 		if (handle->handle != NULL) {
836185db85Sdougm 			handle->scf_state = SCH_STATE_UNINIT;
846185db85Sdougm 			if (unbind)
856185db85Sdougm 				(void) scf_handle_unbind(handle->handle);
866185db85Sdougm 			scf_handle_destroy(handle->handle);
876185db85Sdougm 		}
886185db85Sdougm 		free(handle);
896185db85Sdougm 	}
906185db85Sdougm }
916185db85Sdougm 
926185db85Sdougm /*
936185db85Sdougm  * sa_scf_init()
946185db85Sdougm  *
9525a68471Sdougm  * Must be called before using any of the SCF functions. Called by
966185db85Sdougm  * sa_init() during the API setup.
976185db85Sdougm  */
986185db85Sdougm 
996185db85Sdougm scfutilhandle_t *
100549ec3ffSdougm sa_scf_init(sa_handle_impl_t ihandle)
1016185db85Sdougm {
1026185db85Sdougm 	scfutilhandle_t *handle;
1036185db85Sdougm 
1046185db85Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1056185db85Sdougm 	if (scf_max_name_len <= 0)
1066185db85Sdougm 		scf_max_name_len = SA_MAX_NAME_LEN + 1;
1076185db85Sdougm 
1086185db85Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
10925a68471Sdougm 	if (handle == NULL)
11025a68471Sdougm 		return (handle);
11125a68471Sdougm 
112549ec3ffSdougm 	ihandle->scfhandle = handle;
1136185db85Sdougm 	handle->scf_state = SCH_STATE_INITIALIZING;
1146185db85Sdougm 	handle->handle = scf_handle_create(SCF_VERSION);
11525a68471Sdougm 	if (handle->handle == NULL) {
11625a68471Sdougm 		free(handle);
11725a68471Sdougm 		handle = NULL;
11825a68471Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
11925a68471Sdougm 		    scf_strerror(scf_error()));
12025a68471Sdougm 		return (handle);
12125a68471Sdougm 	}
12225a68471Sdougm 	if (scf_handle_bind(handle->handle) != 0)
12325a68471Sdougm 		goto err;
12425a68471Sdougm 
1256185db85Sdougm 	handle->scope = scf_scope_create(handle->handle);
1266185db85Sdougm 	handle->service = scf_service_create(handle->handle);
1276185db85Sdougm 	handle->pg = scf_pg_create(handle->handle);
128a3351425Sdougm 
12925a68471Sdougm 	/* Make sure we have sufficient SMF running */
1306185db85Sdougm 	handle->instance = scf_instance_create(handle->handle);
131a3351425Sdougm 	if (handle->scope == NULL || handle->service == NULL ||
132a3351425Sdougm 	    handle->pg == NULL || handle->instance == NULL)
133a3351425Sdougm 		goto err;
1346185db85Sdougm 	if (scf_handle_get_scope(handle->handle,
13525a68471Sdougm 	    SCF_SCOPE_LOCAL, handle->scope) != 0)
1366185db85Sdougm 		goto err;
13725a68471Sdougm 	if (scf_scope_get_service(handle->scope,
13825a68471Sdougm 	    SA_GROUP_SVC_NAME, handle->service) != 0)
13925a68471Sdougm 		goto err;
14025a68471Sdougm 
1416185db85Sdougm 	handle->scf_state = SCH_STATE_INIT;
1426185db85Sdougm 	if (sa_get_instance(handle, "default") != SA_OK) {
1436185db85Sdougm 		char **protolist;
1446185db85Sdougm 		int numprotos, i;
1456185db85Sdougm 		sa_group_t defgrp;
14625a68471Sdougm 		defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
1476185db85Sdougm 		if (defgrp != NULL) {
14825a68471Sdougm 			numprotos = sa_get_protocols(
14925a68471Sdougm 			    &protolist);
15025a68471Sdougm 			for (i = 0; i < numprotos; i++)
1516185db85Sdougm 				(void) sa_create_optionset(defgrp,
1526185db85Sdougm 				    protolist[i]);
1536185db85Sdougm 			if (protolist != NULL)
1546185db85Sdougm 				free(protolist);
1556185db85Sdougm 		}
1566185db85Sdougm 	}
15725a68471Sdougm 
1586185db85Sdougm 	return (handle);
1596185db85Sdougm 
16025a68471Sdougm 	/* Error handling/unwinding */
1616185db85Sdougm err:
1626185db85Sdougm 	(void) sa_scf_fini(handle);
1636185db85Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
1646185db85Sdougm 	    scf_strerror(scf_error()));
1656185db85Sdougm 	return (NULL);
1666185db85Sdougm }
1676185db85Sdougm 
1686185db85Sdougm /*
1696185db85Sdougm  * get_scf_limit(name)
1706185db85Sdougm  *
1716185db85Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
1726185db85Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
1736185db85Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
1746185db85Sdougm  * (1024) so we have a reasonable default buffer size.
1756185db85Sdougm  */
1766185db85Sdougm static ssize_t
1776185db85Sdougm get_scf_limit(uint32_t name)
1786185db85Sdougm {
1796185db85Sdougm 	ssize_t vallen;
1806185db85Sdougm 
1816185db85Sdougm 	vallen = scf_limit(name);
1826185db85Sdougm 	if (vallen == (ssize_t)-1)
1836185db85Sdougm 		vallen = MAXPATHLEN;
1846185db85Sdougm 	return (vallen);
1856185db85Sdougm }
1866185db85Sdougm 
1876185db85Sdougm /*
1886185db85Sdougm  * skip_property(name)
1896185db85Sdougm  *
19025a68471Sdougm  * Internal function to check to see if a property is an SMF magic
1916185db85Sdougm  * property that needs to be skipped.
1926185db85Sdougm  */
1936185db85Sdougm static int
1946185db85Sdougm skip_property(char *name)
1956185db85Sdougm {
1966185db85Sdougm 	int i;
1976185db85Sdougm 
1986185db85Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
1996185db85Sdougm 		if (strcmp(name, skip_props[i]) == 0)
2006185db85Sdougm 		return (1);
2016185db85Sdougm 	return (0);
2026185db85Sdougm }
2036185db85Sdougm 
2046185db85Sdougm /*
2056185db85Sdougm  * generate_unique_sharename(sharename)
2066185db85Sdougm  *
2076185db85Sdougm  * Shares are represented in SMF as property groups. Due to share
2086185db85Sdougm  * paths containing characters that are not allowed in SMF names and
2096185db85Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
2106185db85Sdougm  */
2116185db85Sdougm 
2126185db85Sdougm static void
2136185db85Sdougm generate_unique_sharename(char *sharename)
2146185db85Sdougm {
2156185db85Sdougm 	uuid_t uuid;
2166185db85Sdougm 
2176185db85Sdougm 	uuid_generate(uuid);
2186185db85Sdougm 	(void) strcpy(sharename, "S-");
2196185db85Sdougm 	uuid_unparse(uuid, sharename + 2);
2206185db85Sdougm }
2216185db85Sdougm 
2226185db85Sdougm /*
2236185db85Sdougm  * valid_protocol(proto)
2246185db85Sdougm  *
22525a68471Sdougm  * Check to see if the specified protocol is a valid one for the
2266185db85Sdougm  * general sharemgr facility. We determine this by checking which
2276185db85Sdougm  * plugin protocols were found.
2286185db85Sdougm  */
2296185db85Sdougm 
2306185db85Sdougm static int
2316185db85Sdougm valid_protocol(char *proto)
2326185db85Sdougm {
2336185db85Sdougm 	struct sa_proto_plugin *plugin;
2346185db85Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
2356185db85Sdougm 	    plugin = plugin->plugin_next)
2366185db85Sdougm 		if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
2376185db85Sdougm 			return (1);
2386185db85Sdougm 	return (0);
2396185db85Sdougm }
2406185db85Sdougm 
2416185db85Sdougm /*
2426185db85Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2436185db85Sdougm  *
24425a68471Sdougm  * Extract the name property group and create the specified type of
2456185db85Sdougm  * node on the provided group.  type will be optionset or security.
2466185db85Sdougm  */
2476185db85Sdougm 
2486185db85Sdougm static int
2496185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2506185db85Sdougm 			scf_propertygroup_t *pg,
2516185db85Sdougm 			char *nodetype, char *proto, char *sectype)
2526185db85Sdougm {
2536185db85Sdougm 	xmlNodePtr node;
2546185db85Sdougm 	scf_iter_t *iter;
2556185db85Sdougm 	scf_property_t *prop;
2566185db85Sdougm 	scf_value_t *value;
2576185db85Sdougm 	char *name;
2586185db85Sdougm 	char *valuestr;
2596185db85Sdougm 	ssize_t vallen;
2606185db85Sdougm 	int ret = SA_OK;
2616185db85Sdougm 
2626185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2636185db85Sdougm 
2646185db85Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
26525a68471Sdougm 	if (node == NULL)
26625a68471Sdougm 		return (ret);
26725a68471Sdougm 
2686185db85Sdougm 	if (proto != NULL)
2696185db85Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2706185db85Sdougm 	if (sectype != NULL)
2716185db85Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
2726185db85Sdougm 	/*
27325a68471Sdougm 	 * Have node to work with so iterate over the properties
2746185db85Sdougm 	 * in the pg and create option sub nodes.
2756185db85Sdougm 	 */
2766185db85Sdougm 	iter = scf_iter_create(handle->handle);
2776185db85Sdougm 	value = scf_value_create(handle->handle);
2786185db85Sdougm 	prop = scf_property_create(handle->handle);
2796185db85Sdougm 	name = malloc(scf_max_name_len);
2806185db85Sdougm 	valuestr = malloc(vallen);
2816185db85Sdougm 	/*
28225a68471Sdougm 	 * Want to iterate through the properties and add them
2836185db85Sdougm 	 * to the base optionset.
2846185db85Sdougm 	 */
28525a68471Sdougm 	if (iter == NULL || value == NULL || prop == NULL ||
28625a68471Sdougm 	    valuestr == NULL || name == NULL) {
28725a68471Sdougm 		ret = SA_NO_MEMORY;
28825a68471Sdougm 		goto out;
28925a68471Sdougm 	}
2906185db85Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
29125a68471Sdougm 		/* Now iterate the properties in the group */
2926185db85Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
2936185db85Sdougm 			/* have a property */
2946185db85Sdougm 			if (scf_property_get_name(prop, name,
2956185db85Sdougm 			    scf_max_name_len) > 0) {
29625a68471Sdougm 				sa_property_t saprop;
29725a68471Sdougm 				/* Some properties are part of the framework */
2986185db85Sdougm 				if (skip_property(name))
2996185db85Sdougm 					continue;
30025a68471Sdougm 				if (scf_property_get_value(prop, value) != 0)
30125a68471Sdougm 					continue;
3026185db85Sdougm 				if (scf_value_get_astring(value, valuestr,
30325a68471Sdougm 				    vallen) < 0)
30425a68471Sdougm 					continue;
30525a68471Sdougm 				saprop = sa_create_property(name, valuestr);
3066185db85Sdougm 				if (saprop != NULL) {
3076185db85Sdougm 					/*
30825a68471Sdougm 					 * Since in SMF, don't
3096185db85Sdougm 					 * recurse. Use xmlAddChild
3106185db85Sdougm 					 * directly, instead.
3116185db85Sdougm 					 */
3126185db85Sdougm 					xmlAddChild(node,
3136185db85Sdougm 					    (xmlNodePtr) saprop);
3146185db85Sdougm 				}
3156185db85Sdougm 			}
3166185db85Sdougm 		}
3176185db85Sdougm 	}
31825a68471Sdougm out:
3196185db85Sdougm 	/* cleanup to avoid memory leaks */
3206185db85Sdougm 	if (value != NULL)
3216185db85Sdougm 		scf_value_destroy(value);
3226185db85Sdougm 	if (iter != NULL)
3236185db85Sdougm 		scf_iter_destroy(iter);
3246185db85Sdougm 	if (prop != NULL)
3256185db85Sdougm 		scf_property_destroy(prop);
3266185db85Sdougm 	if (name != NULL)
3276185db85Sdougm 		free(name);
3286185db85Sdougm 	if (valuestr != NULL)
3296185db85Sdougm 		free(valuestr);
33025a68471Sdougm 
3316185db85Sdougm 	return (ret);
3326185db85Sdougm }
3336185db85Sdougm 
3346185db85Sdougm /*
3356185db85Sdougm  * sa_extract_attrs(root, handle, instance)
3366185db85Sdougm  *
33725a68471Sdougm  * Local function to extract the actual attributes/properties from the
3386185db85Sdougm  * property group of the service instance. These are the well known
3396185db85Sdougm  * attributes of "state" and "zfs". If additional attributes are
3406185db85Sdougm  * added, they should be added here.
3416185db85Sdougm  */
3426185db85Sdougm 
3436185db85Sdougm static void
3446185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3456185db85Sdougm 		    scf_instance_t *instance)
3466185db85Sdougm {
3476185db85Sdougm 	scf_property_t *prop;
3486185db85Sdougm 	scf_value_t *value;
3496185db85Sdougm 	char *valuestr;
3506185db85Sdougm 	ssize_t vallen;
3516185db85Sdougm 
3526185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3536185db85Sdougm 	prop = scf_property_create(handle->handle);
3546185db85Sdougm 	value = scf_value_create(handle->handle);
3556185db85Sdougm 	valuestr = malloc(vallen);
35625a68471Sdougm 	if (prop == NULL || value == NULL || valuestr == NULL ||
35725a68471Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
35825a68471Sdougm 		goto out;
35925a68471Sdougm 	}
3606185db85Sdougm 	/*
36125a68471Sdougm 	 * Have a property group with desired name so now get
3626185db85Sdougm 	 * the known attributes.
3636185db85Sdougm 	 */
3646185db85Sdougm 	if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
36525a68471Sdougm 		/* Found the property so get the value */
3666185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
36725a68471Sdougm 			if (scf_value_get_astring(value, valuestr,
36825a68471Sdougm 			    vallen) >= 0) {
3696185db85Sdougm 				xmlSetProp(root, (xmlChar *)"state",
3706185db85Sdougm 				    (xmlChar *)valuestr);
3716185db85Sdougm 			}
3726185db85Sdougm 		}
3736185db85Sdougm 	}
3746185db85Sdougm 	if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
37525a68471Sdougm 		/* Found the property so get the value */
3766185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
37725a68471Sdougm 			if (scf_value_get_astring(value, valuestr,
37825a68471Sdougm 			    vallen) > 0) {
3796185db85Sdougm 				xmlSetProp(root, (xmlChar *)"zfs",
3806185db85Sdougm 				    (xmlChar *)valuestr);
3816185db85Sdougm 			}
3826185db85Sdougm 		}
3836185db85Sdougm 	}
38425a68471Sdougm out:
3856185db85Sdougm 	if (valuestr != NULL)
3866185db85Sdougm 		free(valuestr);
3876185db85Sdougm 	if (value != NULL)
3886185db85Sdougm 		scf_value_destroy(value);
3896185db85Sdougm 	if (prop != NULL)
3906185db85Sdougm 		scf_property_destroy(prop);
3916185db85Sdougm }
3926185db85Sdougm 
3936185db85Sdougm /*
39425a68471Sdougm  * List of known share attributes.
3956185db85Sdougm  */
3966185db85Sdougm 
3976185db85Sdougm static char *share_attr[] = {
3986185db85Sdougm 	"path",
3996185db85Sdougm 	"id",
400*da6c28aaSamw 	"drive-letter",
401*da6c28aaSamw 	"exclude",
4026185db85Sdougm 	NULL,
4036185db85Sdougm };
4046185db85Sdougm 
4056185db85Sdougm static int
4066185db85Sdougm is_share_attr(char *name)
4076185db85Sdougm {
4086185db85Sdougm 	int i;
4096185db85Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
4106185db85Sdougm 		if (strcmp(name, share_attr[i]) == 0)
4116185db85Sdougm 			return (1);
4126185db85Sdougm 	return (0);
4136185db85Sdougm }
4146185db85Sdougm 
4156185db85Sdougm /*
416*da6c28aaSamw  * _sa_make_resource(node, valuestr)
417*da6c28aaSamw  *
418*da6c28aaSamw  * Make a resource node on the share node. The valusestr will either
419*da6c28aaSamw  * be old format (SMF acceptable string) or new format (pretty much an
420*da6c28aaSamw  * arbitrary string with "nnn:" prefixing in order to persist
421*da6c28aaSamw  * mapping). The input valuestr will get modified in place. This is
422*da6c28aaSamw  * only used in SMF repository parsing. A possible third field will be
423*da6c28aaSamw  * a "description" string.
424*da6c28aaSamw  */
425*da6c28aaSamw 
426*da6c28aaSamw static void
427*da6c28aaSamw _sa_make_resource(xmlNodePtr node, char *valuestr)
428*da6c28aaSamw {
429*da6c28aaSamw 	char *idx;
430*da6c28aaSamw 	char *name;
431*da6c28aaSamw 	char *description = NULL;
432*da6c28aaSamw 
433*da6c28aaSamw 	idx = valuestr;
434*da6c28aaSamw 	name = strchr(valuestr, ':');
435*da6c28aaSamw 	if (name == NULL) {
436*da6c28aaSamw 		/* this is old form so give an index of "0" */
437*da6c28aaSamw 		idx = "0";
438*da6c28aaSamw 		name = valuestr;
439*da6c28aaSamw 	} else {
440*da6c28aaSamw 		/* NUL the ':' and move past it */
441*da6c28aaSamw 		*name++ = '\0';
442*da6c28aaSamw 		/* There could also be a description string */
443*da6c28aaSamw 		description = strchr(name, ':');
444*da6c28aaSamw 		if (description != NULL)
445*da6c28aaSamw 			*description++ = '\0';
446*da6c28aaSamw 	}
447*da6c28aaSamw 	node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
448*da6c28aaSamw 	if (node != NULL) {
449*da6c28aaSamw 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
450*da6c28aaSamw 		xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
451*da6c28aaSamw 		/* SMF values are always persistent */
452*da6c28aaSamw 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
453*da6c28aaSamw 		if (description != NULL && strlen(description) > 0) {
454*da6c28aaSamw 			(void) xmlNewChild(node, NULL, (xmlChar *)"description",
455*da6c28aaSamw 			    (xmlChar *)description);
456*da6c28aaSamw 		}
457*da6c28aaSamw 	}
458*da6c28aaSamw }
459*da6c28aaSamw 
460*da6c28aaSamw 
461*da6c28aaSamw /*
4626185db85Sdougm  * sa_share_from_pgroup
4636185db85Sdougm  *
46425a68471Sdougm  * Extract the share definition from the share property group. We do
4656185db85Sdougm  * some sanity checking to avoid bad data.
4666185db85Sdougm  *
4676185db85Sdougm  * Since this is only constructing the internal data structures, we
4686185db85Sdougm  * don't use the sa_* functions most of the time.
4696185db85Sdougm  */
4706185db85Sdougm void
4716185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4726185db85Sdougm 			scf_propertygroup_t *pg, char *id)
4736185db85Sdougm {
4746185db85Sdougm 	xmlNodePtr node;
4756185db85Sdougm 	char *name;
4766185db85Sdougm 	scf_iter_t *iter;
4776185db85Sdougm 	scf_property_t *prop;
4786185db85Sdougm 	scf_value_t *value;
4796185db85Sdougm 	ssize_t vallen;
4806185db85Sdougm 	char *valuestr;
4816185db85Sdougm 	int ret = SA_OK;
482f345c0beSdougm 	int have_path = 0;
4836185db85Sdougm 
4846185db85Sdougm 	/*
4856185db85Sdougm 	 * While preliminary check (starts with 'S') passed before
4866185db85Sdougm 	 * getting here. Need to make sure it is in ID syntax
4876185db85Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
4886185db85Sdougm 	 * pgroups.
4896185db85Sdougm 	 */
4906185db85Sdougm 	vallen = strlen(id);
4916185db85Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
4926185db85Sdougm 		uuid_t uuid;
49325a68471Sdougm 		if (strncmp(id, SA_SHARE_PG_PREFIX,
49425a68471Sdougm 		    SA_SHARE_PG_PREFIXLEN) != 0 ||
4956185db85Sdougm 		    uuid_parse(id + 2, uuid) < 0)
4966185db85Sdougm 			return;
4976185db85Sdougm 	} else {
4986185db85Sdougm 		return;
4996185db85Sdougm 	}
5006185db85Sdougm 
5016185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
5026185db85Sdougm 
5036185db85Sdougm 	iter = scf_iter_create(handle->handle);
5046185db85Sdougm 	value = scf_value_create(handle->handle);
5056185db85Sdougm 	prop = scf_property_create(handle->handle);
5066185db85Sdougm 	name = malloc(scf_max_name_len);
5076185db85Sdougm 	valuestr = malloc(vallen);
5086185db85Sdougm 
5096185db85Sdougm 	/*
51025a68471Sdougm 	 * Construct the share XML node. It is similar to sa_add_share
5116185db85Sdougm 	 * but never changes the repository. Also, there won't be any
5126185db85Sdougm 	 * ZFS or transient shares.  Root will be the group it is
5136185db85Sdougm 	 * associated with.
5146185db85Sdougm 	 */
5156185db85Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
5166185db85Sdougm 	if (node != NULL) {
5176185db85Sdougm 		/*
51825a68471Sdougm 		 * Make sure the UUID part of the property group is
5196185db85Sdougm 		 * stored in the share "id" property. We use this
5206185db85Sdougm 		 * later.
5216185db85Sdougm 		 */
5226185db85Sdougm 		xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
5236185db85Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
5246185db85Sdougm 	}
5256185db85Sdougm 
52625a68471Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
52725a68471Sdougm 		goto out;
52825a68471Sdougm 
52925a68471Sdougm 	/* Iterate over the share pg properties */
53025a68471Sdougm 	if (scf_iter_pg_properties(iter, pg) != 0)
53125a68471Sdougm 		goto out;
53225a68471Sdougm 
5336185db85Sdougm 	while (scf_iter_next_property(iter, prop) > 0) {
5346185db85Sdougm 		ret = SA_SYSTEM_ERR; /* assume the worst */
53525a68471Sdougm 		if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
5366185db85Sdougm 			if (scf_property_get_value(prop, value) == 0) {
5376185db85Sdougm 				if (scf_value_get_astring(value, valuestr,
5386185db85Sdougm 				    vallen) >= 0) {
5396185db85Sdougm 					ret = SA_OK;
5406185db85Sdougm 				}
541*da6c28aaSamw 			} else if (strcmp(name, "resource") == 0) {
542*da6c28aaSamw 				ret = SA_OK;
5436185db85Sdougm 			}
5446185db85Sdougm 		}
545*da6c28aaSamw 		if (ret != SA_OK)
546*da6c28aaSamw 			continue;
547f345c0beSdougm 		/*
54825a68471Sdougm 		 * Check that we have the "path" property in
549f345c0beSdougm 		 * name. The string in name will always be nul
550f345c0beSdougm 		 * terminated if scf_property_get_name()
551f345c0beSdougm 		 * succeeded.
552f345c0beSdougm 		 */
553f345c0beSdougm 		if (strcmp(name, "path") == 0)
554f345c0beSdougm 			have_path = 1;
5556185db85Sdougm 		if (is_share_attr(name)) {
5566185db85Sdougm 			/*
55725a68471Sdougm 			 * If a share attr, then simple -
558*da6c28aaSamw 			 * usually path and id name
5596185db85Sdougm 			 */
5606185db85Sdougm 			xmlSetProp(node, (xmlChar *)name,
5616185db85Sdougm 			    (xmlChar *)valuestr);
562*da6c28aaSamw 		} else if (strcmp(name, "resource") == 0) {
563*da6c28aaSamw 			/*
564*da6c28aaSamw 			 * Resource names handled differently since
565*da6c28aaSamw 			 * there can be multiple on each share. The
566*da6c28aaSamw 			 * "resource" id must be preserved since this
567*da6c28aaSamw 			 * will be used by some protocols in mapping
568*da6c28aaSamw 			 * "property spaces" to names and is always
569*da6c28aaSamw 			 * used to create SMF property groups specific
570*da6c28aaSamw 			 * to resources.  CIFS needs this.  The first
571*da6c28aaSamw 			 * value is present so add and then loop for
572*da6c28aaSamw 			 * any additional. Since this is new and
573*da6c28aaSamw 			 * previous values may exist, handle
574*da6c28aaSamw 			 * conversions.
575*da6c28aaSamw 			 */
576*da6c28aaSamw 			scf_iter_t *viter;
577*da6c28aaSamw 			viter = scf_iter_create(handle->handle);
578*da6c28aaSamw 			if (viter != NULL &&
579*da6c28aaSamw 			    scf_iter_property_values(viter, prop) == 0) {
580*da6c28aaSamw 				while (scf_iter_next_value(viter, value) > 0) {
581*da6c28aaSamw 					/* Have a value so process it */
582*da6c28aaSamw 					if (scf_value_get_ustring(value,
583*da6c28aaSamw 					    valuestr, vallen) >= 0) {
584*da6c28aaSamw 						/* have a ustring */
585*da6c28aaSamw 						_sa_make_resource(node,
586*da6c28aaSamw 						    valuestr);
587*da6c28aaSamw 					} else if (scf_value_get_astring(value,
588*da6c28aaSamw 					    valuestr, vallen) >= 0) {
589*da6c28aaSamw 						/* have an astring */
590*da6c28aaSamw 						_sa_make_resource(node,
591*da6c28aaSamw 						    valuestr);
592*da6c28aaSamw 					}
593*da6c28aaSamw 				}
594*da6c28aaSamw 				scf_iter_destroy(viter);
595*da6c28aaSamw 			}
5966185db85Sdougm 		} else {
5976185db85Sdougm 			if (strcmp(name, "description") == 0) {
59825a68471Sdougm 				/* We have a description node */
5996185db85Sdougm 				xmlNodePtr desc;
6006185db85Sdougm 				desc = xmlNewChild(node, NULL,
60125a68471Sdougm 				    (xmlChar *)"description", NULL);
6026185db85Sdougm 				if (desc != NULL)
6036185db85Sdougm 					xmlNodeSetContent(desc,
6046185db85Sdougm 					    (xmlChar *)valuestr);
6056185db85Sdougm 			}
6066185db85Sdougm 		}
6076185db85Sdougm 	}
60825a68471Sdougm out:
609f345c0beSdougm 	/*
61025a68471Sdougm 	 * A share without a path is broken so we want to not include
611f345c0beSdougm 	 * these.  They shouldn't happen but if you kill a sharemgr in
612f345c0beSdougm 	 * the process of creating a share, it could happen.  They
613f345c0beSdougm 	 * should be harmless.  It is also possible that another
614f345c0beSdougm 	 * sharemgr is running and in the process of creating a share.
615f345c0beSdougm 	 */
616f345c0beSdougm 	if (have_path == 0 && node != NULL) {
617f345c0beSdougm 		xmlUnlinkNode(node);
618f345c0beSdougm 		xmlFreeNode(node);
619f345c0beSdougm 	}
6206185db85Sdougm 	if (name != NULL)
6216185db85Sdougm 		free(name);
6226185db85Sdougm 	if (valuestr != NULL)
6236185db85Sdougm 		free(valuestr);
6246185db85Sdougm 	if (value != NULL)
6256185db85Sdougm 		scf_value_destroy(value);
6266185db85Sdougm 	if (iter != NULL)
6276185db85Sdougm 		scf_iter_destroy(iter);
6286185db85Sdougm 	if (prop != NULL)
6296185db85Sdougm 		scf_property_destroy(prop);
6306185db85Sdougm }
6316185db85Sdougm 
6326185db85Sdougm /*
6336185db85Sdougm  * find_share_by_id(shareid)
6346185db85Sdougm  *
6356185db85Sdougm  * Search all shares in all groups until we find the share represented
6366185db85Sdougm  * by "id".
6376185db85Sdougm  */
6386185db85Sdougm 
6396185db85Sdougm static sa_share_t
640549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid)
6416185db85Sdougm {
6426185db85Sdougm 	sa_group_t group;
6436185db85Sdougm 	sa_share_t share = NULL;
6446185db85Sdougm 	char *id = NULL;
6456185db85Sdougm 	int done = 0;
6466185db85Sdougm 
64725a68471Sdougm 	for (group = sa_get_group(handle, NULL);
64825a68471Sdougm 	    group != NULL && !done;
6496185db85Sdougm 	    group = sa_get_next_group(group)) {
65025a68471Sdougm 		for (share = sa_get_share(group, NULL);
65125a68471Sdougm 		    share != NULL;
6526185db85Sdougm 		    share = sa_get_next_share(share)) {
6536185db85Sdougm 			id = sa_get_share_attr(share, "id");
6546185db85Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
6556185db85Sdougm 				sa_free_attr_string(id);
6566185db85Sdougm 				id = NULL;
6576185db85Sdougm 				done++;
6586185db85Sdougm 				break;
6596185db85Sdougm 			}
6606185db85Sdougm 			if (id != NULL) {
6616185db85Sdougm 				sa_free_attr_string(id);
6626185db85Sdougm 				id = NULL;
6636185db85Sdougm 			}
6646185db85Sdougm 		}
6656185db85Sdougm 	}
6666185db85Sdougm 	return (share);
6676185db85Sdougm }
6686185db85Sdougm 
6696185db85Sdougm /*
670*da6c28aaSamw  * find_resource_by_index(share, index)
671*da6c28aaSamw  *
672*da6c28aaSamw  * Search the resource records on the share for the id index.
673*da6c28aaSamw  */
674*da6c28aaSamw static sa_resource_t
675*da6c28aaSamw find_resource_by_index(sa_share_t share, char *index)
676*da6c28aaSamw {
677*da6c28aaSamw 	sa_resource_t resource;
678*da6c28aaSamw 	sa_resource_t found = NULL;
679*da6c28aaSamw 	char *id;
680*da6c28aaSamw 
681*da6c28aaSamw 	for (resource = sa_get_share_resource(share, NULL);
682*da6c28aaSamw 	    resource != NULL && found == NULL;
683*da6c28aaSamw 	    resource = sa_get_next_resource(resource)) {
684*da6c28aaSamw 		id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
685*da6c28aaSamw 		if (id != NULL) {
686*da6c28aaSamw 			if (strcmp(id, index) == 0) {
687*da6c28aaSamw 				/* found it so save in "found" */
688*da6c28aaSamw 				found = resource;
689*da6c28aaSamw 			}
690*da6c28aaSamw 			sa_free_attr_string(id);
691*da6c28aaSamw 		}
692*da6c28aaSamw 	}
693*da6c28aaSamw 	return (found);
694*da6c28aaSamw }
695*da6c28aaSamw 
696*da6c28aaSamw /*
697*da6c28aaSamw  * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
6986185db85Sdougm  *
69925a68471Sdougm  * Extract share properties from the SMF property group. More sanity
7006185db85Sdougm  * checks are done and the share object is created. We ignore some
7016185db85Sdougm  * errors that could exist in the repository and only worry about
7026185db85Sdougm  * property groups that validate in naming.
7036185db85Sdougm  */
7046185db85Sdougm 
7056185db85Sdougm static int
7066185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
707549ec3ffSdougm 			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
7086185db85Sdougm {
7096185db85Sdougm 	xmlNodePtr node;
71025a68471Sdougm 	char *name = NULL;
71125a68471Sdougm 	scf_iter_t *iter = NULL;
71225a68471Sdougm 	scf_property_t *prop = NULL;
71325a68471Sdougm 	scf_value_t *value = NULL;
7146185db85Sdougm 	ssize_t vallen;
71525a68471Sdougm 	char *valuestr = NULL;
7166185db85Sdougm 	int ret = SA_OK;
7176185db85Sdougm 	char *sectype = NULL;
7186185db85Sdougm 	char *proto;
7196185db85Sdougm 	sa_share_t share;
72025a68471Sdougm 	uuid_t uuid;
7216185db85Sdougm 
7226185db85Sdougm 	/*
7236185db85Sdougm 	 * While preliminary check (starts with 'S') passed before
7246185db85Sdougm 	 * getting here. Need to make sure it is in ID syntax
7256185db85Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
7266185db85Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
7276185db85Sdougm 	 * characters, it is likely one of the protocol/security
7286185db85Sdougm 	 * versions.
7296185db85Sdougm 	 */
7306185db85Sdougm 	vallen = strlen(id);
73125a68471Sdougm 	if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
73225a68471Sdougm 		/*
73325a68471Sdougm 		 * It is ok to not have what we thought since someone might
73425a68471Sdougm 		 * have added a name via SMF.
73525a68471Sdougm 		 */
73625a68471Sdougm 		return (ret);
73725a68471Sdougm 	}
7386185db85Sdougm 	if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
7396185db85Sdougm 		proto = strchr(id, '_');
7406185db85Sdougm 		if (proto == NULL)
7416185db85Sdougm 			return (ret);
7426185db85Sdougm 		*proto++ = '\0';
7436185db85Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
7446185db85Sdougm 			return (ret);
7456185db85Sdougm 		/*
7466185db85Sdougm 		 * probably a legal optionset so check a few more
7476185db85Sdougm 		 * syntax points below.
7486185db85Sdougm 		 */
7496185db85Sdougm 		if (*proto == '\0') {
7506185db85Sdougm 			/* not a valid proto (null) */
7516185db85Sdougm 			return (ret);
7526185db85Sdougm 		}
753*da6c28aaSamw 
7546185db85Sdougm 		sectype = strchr(proto, '_');
7556185db85Sdougm 		if (sectype != NULL)
7566185db85Sdougm 			*sectype++ = '\0';
7576185db85Sdougm 		if (!valid_protocol(proto))
7586185db85Sdougm 			return (ret);
7596185db85Sdougm 	}
7606185db85Sdougm 
7616185db85Sdougm 	/*
76225a68471Sdougm 	 * To get here, we have a valid protocol and possibly a
7636185db85Sdougm 	 * security. We now have to find the share that it is really
7646185db85Sdougm 	 * associated with. The "id" portion of the pgroup name will
7656185db85Sdougm 	 * match.
7666185db85Sdougm 	 */
7676185db85Sdougm 
768549ec3ffSdougm 	share = find_share_by_id(sahandle, id);
7696185db85Sdougm 	if (share == NULL)
7706185db85Sdougm 		return (SA_BAD_PATH);
7716185db85Sdougm 
7726185db85Sdougm 	root = (xmlNodePtr)share;
7736185db85Sdougm 
7746185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
7756185db85Sdougm 
77625a68471Sdougm 	if (sectype == NULL)
77725a68471Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
77825a68471Sdougm 	else {
779*da6c28aaSamw 		if (isdigit((int)*sectype)) {
780*da6c28aaSamw 			sa_resource_t resource;
781*da6c28aaSamw 			/*
782*da6c28aaSamw 			 * If sectype[0] is a digit, then it is an index into
783*da6c28aaSamw 			 * the resource names. We need to find a resource
784*da6c28aaSamw 			 * record and then get the properties into an
785*da6c28aaSamw 			 * optionset. The optionset becomes the "node" and the
786*da6c28aaSamw 			 * rest is hung off of the share.
787*da6c28aaSamw 			 */
788*da6c28aaSamw 			resource = find_resource_by_index(share, sectype);
789*da6c28aaSamw 			if (resource != NULL) {
790*da6c28aaSamw 				node = xmlNewChild(resource, NULL,
791*da6c28aaSamw 				    (xmlChar *)"optionset", NULL);
792*da6c28aaSamw 			} else {
793*da6c28aaSamw 				/* this shouldn't happen */
794*da6c28aaSamw 				ret = SA_SYSTEM_ERR;
795*da6c28aaSamw 			}
796*da6c28aaSamw 		} else {
797*da6c28aaSamw 			/*
798*da6c28aaSamw 			 * If not a digit, then it is a security type
799*da6c28aaSamw 			 * (alternate option space). Security types start with
800*da6c28aaSamw 			 * an alphabetic.
801*da6c28aaSamw 			 */
802*da6c28aaSamw 			node = xmlNewChild(root, NULL, (xmlChar *)"security",
803*da6c28aaSamw 			    NULL);
80425a68471Sdougm 			if (node != NULL)
80525a68471Sdougm 				xmlSetProp(node, (xmlChar *)"sectype",
80625a68471Sdougm 				    (xmlChar *)sectype);
80725a68471Sdougm 		}
808*da6c28aaSamw 	}
80925a68471Sdougm 	if (node == NULL) {
81025a68471Sdougm 		ret = SA_NO_MEMORY;
81125a68471Sdougm 		goto out;
81225a68471Sdougm 	}
81325a68471Sdougm 
81425a68471Sdougm 	xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
81525a68471Sdougm 	/* now find the properties */
8166185db85Sdougm 	iter = scf_iter_create(handle->handle);
8176185db85Sdougm 	value = scf_value_create(handle->handle);
8186185db85Sdougm 	prop = scf_property_create(handle->handle);
8196185db85Sdougm 	name = malloc(scf_max_name_len);
8206185db85Sdougm 	valuestr = malloc(vallen);
8216185db85Sdougm 
82225a68471Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
82325a68471Sdougm 		goto out;
82425a68471Sdougm 
825*da6c28aaSamw 	/* iterate over the share pg properties */
8266185db85Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
8276185db85Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
8286185db85Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
8296185db85Sdougm 			if (scf_property_get_name(prop, name,
8306185db85Sdougm 			    scf_max_name_len) > 0) {
8316185db85Sdougm 				if (scf_property_get_value(prop, value) == 0) {
83225a68471Sdougm 					if (scf_value_get_astring(value,
83325a68471Sdougm 					    valuestr, vallen) >= 0) {
8346185db85Sdougm 						ret = SA_OK;
8356185db85Sdougm 					}
8366185db85Sdougm 				}
8376185db85Sdougm 			} else {
8386185db85Sdougm 				ret = SA_SYSTEM_ERR;
8396185db85Sdougm 			}
8406185db85Sdougm 			if (ret == SA_OK) {
8416185db85Sdougm 				sa_property_t prop;
8426185db85Sdougm 				prop = sa_create_property(name, valuestr);
8436185db85Sdougm 				if (prop != NULL)
8446185db85Sdougm 					prop = (sa_property_t)xmlAddChild(node,
8456185db85Sdougm 					    (xmlNodePtr)prop);
8466185db85Sdougm 				else
8476185db85Sdougm 					ret = SA_NO_MEMORY;
8486185db85Sdougm 			}
8496185db85Sdougm 		}
8506185db85Sdougm 	} else {
8516185db85Sdougm 		ret = SA_SYSTEM_ERR;
8526185db85Sdougm 	}
85325a68471Sdougm out:
8546185db85Sdougm 	if (iter != NULL)
8556185db85Sdougm 		scf_iter_destroy(iter);
8566185db85Sdougm 	if (value != NULL)
8576185db85Sdougm 		scf_value_destroy(value);
8586185db85Sdougm 	if (prop != NULL)
8596185db85Sdougm 		scf_property_destroy(prop);
8606185db85Sdougm 	if (name != NULL)
8616185db85Sdougm 		free(name);
8626185db85Sdougm 	if (valuestr != NULL)
8636185db85Sdougm 		free(valuestr);
8646185db85Sdougm 	return (ret);
8656185db85Sdougm }
8666185db85Sdougm 
8676185db85Sdougm /*
8686185db85Sdougm  * sa_extract_group(root, handle, instance)
8696185db85Sdougm  *
87025a68471Sdougm  * Get the config info for this instance of a group and create the XML
8716185db85Sdougm  * subtree from it.
8726185db85Sdougm  */
8736185db85Sdougm 
8746185db85Sdougm static int
8756185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
876549ec3ffSdougm 			scf_instance_t *instance, sa_handle_t sahandle)
8776185db85Sdougm {
8786185db85Sdougm 	char *buff;
8796185db85Sdougm 	xmlNodePtr node;
8806185db85Sdougm 	scf_iter_t *iter;
8816185db85Sdougm 	char *proto;
8826185db85Sdougm 	char *sectype;
8836185db85Sdougm 	int have_shares = 0;
8846185db85Sdougm 	int has_proto = 0;
8856185db85Sdougm 	int is_default = 0;
8866185db85Sdougm 	int ret = SA_OK;
8876185db85Sdougm 	int err;
8886185db85Sdougm 
8896185db85Sdougm 	buff = malloc(scf_max_name_len);
89025a68471Sdougm 	if (buff == NULL)
89125a68471Sdougm 		return (SA_NO_MEMORY);
89225a68471Sdougm 
8936185db85Sdougm 	iter = scf_iter_create(handle->handle);
89425a68471Sdougm 	if (iter == NULL) {
89525a68471Sdougm 		ret = SA_NO_MEMORY;
89625a68471Sdougm 		goto out;
89725a68471Sdougm 	}
89825a68471Sdougm 
89925a68471Sdougm 	if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
9006185db85Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
90125a68471Sdougm 		if (node == NULL) {
90225a68471Sdougm 			ret = SA_NO_MEMORY;
90325a68471Sdougm 			goto out;
90425a68471Sdougm 		}
9056185db85Sdougm 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
9066185db85Sdougm 		if (strcmp(buff, "default") == 0)
9076185db85Sdougm 			is_default++;
90825a68471Sdougm 
9096185db85Sdougm 		sa_extract_attrs(node, handle, instance);
9106185db85Sdougm 		/*
9116185db85Sdougm 		 * Iterate through all the property groups
9126185db85Sdougm 		 * looking for those with security or
9136185db85Sdougm 		 * optionset prefixes. The names of the
9146185db85Sdougm 		 * matching pgroups are parsed to get the
9156185db85Sdougm 		 * protocol, and for security, the sectype.
9166185db85Sdougm 		 * Syntax is as follows:
9176185db85Sdougm 		 *    optionset | optionset_<proto>
9186185db85Sdougm 		 *    security_default | security_<proto>_<sectype>
9196185db85Sdougm 		 * "operation" is handled by
9206185db85Sdougm 		 * sa_extract_attrs().
9216185db85Sdougm 		 */
92225a68471Sdougm 		if (scf_iter_instance_pgs(iter, instance) != 0) {
92325a68471Sdougm 			ret = SA_NO_MEMORY;
92425a68471Sdougm 			goto out;
92525a68471Sdougm 		}
9266185db85Sdougm 		while (scf_iter_next_pg(iter, handle->pg) > 0) {
92725a68471Sdougm 			/* Have a pgroup so sort it out */
9286185db85Sdougm 			ret = scf_pg_get_name(handle->pg, buff,
9296185db85Sdougm 			    scf_max_name_len);
9306185db85Sdougm 			if (ret  > 0) {
9316185db85Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
9326185db85Sdougm 					sa_share_from_pgroup(node, handle,
93325a68471Sdougm 					    handle->pg, buff);
9346185db85Sdougm 					have_shares++;
9356185db85Sdougm 				} else if (strncmp(buff, "optionset", 9) ==
9366185db85Sdougm 				    0) {
9376185db85Sdougm 					char *nodetype = "optionset";
93825a68471Sdougm 					/* Have an optionset */
9396185db85Sdougm 					sectype = NULL;
9406185db85Sdougm 					proto = strchr(buff, '_');
9416185db85Sdougm 					if (proto != NULL) {
9426185db85Sdougm 						*proto++ = '\0';
9436185db85Sdougm 						sectype = strchr(proto, '_');
9446185db85Sdougm 						if (sectype != NULL) {
9456185db85Sdougm 							*sectype++ = '\0';
9466185db85Sdougm 							nodetype = "security";
9476185db85Sdougm 						}
9486185db85Sdougm 					}
9496185db85Sdougm 					ret = sa_extract_pgroup(node, handle,
95025a68471Sdougm 					    handle->pg, nodetype, proto,
95125a68471Sdougm 					    sectype);
9526185db85Sdougm 					has_proto++;
95325a68471Sdougm 				} else if (strncmp(buff, "security", 8) == 0) {
9546185db85Sdougm 					/*
95525a68471Sdougm 					 * Have a security (note that
9566185db85Sdougm 					 * this should change in the
9576185db85Sdougm 					 * future)
9586185db85Sdougm 					 */
9596185db85Sdougm 					proto = strchr(buff, '_');
9606185db85Sdougm 					sectype = NULL;
9616185db85Sdougm 					if (proto != NULL) {
9626185db85Sdougm 						*proto++ = '\0';
9636185db85Sdougm 						sectype = strchr(proto, '_');
9646185db85Sdougm 						if (sectype != NULL)
9656185db85Sdougm 							*sectype++ = '\0';
96625a68471Sdougm 						if (strcmp(proto, "default") ==
96725a68471Sdougm 						    0)
9686185db85Sdougm 							proto = NULL;
9696185db85Sdougm 					}
9706185db85Sdougm 					ret = sa_extract_pgroup(node, handle,
97125a68471Sdougm 					    handle->pg, "security", proto,
9726185db85Sdougm 					    sectype);
9736185db85Sdougm 					has_proto++;
9746185db85Sdougm 				}
97525a68471Sdougm 				/* Ignore everything else */
9766185db85Sdougm 			}
9776185db85Sdougm 		}
9786185db85Sdougm 		/*
9796185db85Sdougm 		 * Make sure we have a valid default group.
9806185db85Sdougm 		 * On first boot, default won't have any
9816185db85Sdougm 		 * protocols defined and won't be enabled (but
9826185db85Sdougm 		 * should be).
9836185db85Sdougm 		 */
9846185db85Sdougm 		if (is_default) {
9856185db85Sdougm 			char *state = sa_get_group_attr((sa_group_t)node,
9866185db85Sdougm 			    "state");
9876185db85Sdougm 			char **protos;
9886185db85Sdougm 			int numprotos;
9896185db85Sdougm 			int i;
9906185db85Sdougm 
9916185db85Sdougm 			if (state == NULL) {
9926185db85Sdougm 				/* set attribute to enabled */
9936185db85Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
99425a68471Sdougm 				    "state", "enabled");
99525a68471Sdougm 				/* We can assume no protocols */
9966185db85Sdougm 				numprotos = sa_get_protocols(&protos);
9976185db85Sdougm 				for (i = 0; i < numprotos; i++)
99825a68471Sdougm 					(void) sa_create_optionset(
99925a68471Sdougm 					    (sa_group_t)node, protos[i]);
10006185db85Sdougm 				if (numprotos > 0)
10016185db85Sdougm 					free(protos);
10026185db85Sdougm 			} else {
10036185db85Sdougm 				sa_free_attr_string(state);
10046185db85Sdougm 			}
10056185db85Sdougm 		}
100625a68471Sdougm 		/* Do a second pass if shares were found */
100725a68471Sdougm 		if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
10086185db85Sdougm 			while (scf_iter_next_pg(iter, handle->pg) > 0) {
10096185db85Sdougm 				/*
101025a68471Sdougm 				 * Have a pgroup so see if it is a
10116185db85Sdougm 				 * share optionset
10126185db85Sdougm 				 */
10136185db85Sdougm 				err = scf_pg_get_name(handle->pg, buff,
10146185db85Sdougm 				    scf_max_name_len);
101525a68471Sdougm 				if (err  <= 0)
101625a68471Sdougm 					continue;
10176185db85Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
10186185db85Sdougm 					ret = sa_share_props_from_pgroup(node,
101925a68471Sdougm 					    handle, handle->pg, buff,
102025a68471Sdougm 					    sahandle);
10216185db85Sdougm 				}
10226185db85Sdougm 			}
10236185db85Sdougm 		}
10246185db85Sdougm 	}
102525a68471Sdougm out:
10266185db85Sdougm 	if (iter != NULL)
10276185db85Sdougm 		scf_iter_destroy(iter);
10286185db85Sdougm 	if (buff != NULL)
10296185db85Sdougm 		free(buff);
10306185db85Sdougm 	return (ret);
10316185db85Sdougm }
10326185db85Sdougm 
10336185db85Sdougm /*
10346185db85Sdougm  * sa_extract_defaults(root, handle, instance)
10356185db85Sdougm  *
103625a68471Sdougm  * Local function to find the default properties that live in the
1037*da6c28aaSamw  * default instance's "operation" property group.
10386185db85Sdougm  */
10396185db85Sdougm 
10406185db85Sdougm static void
10416185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
10426185db85Sdougm 		    scf_instance_t *instance)
10436185db85Sdougm {
10446185db85Sdougm 	xmlNodePtr node;
10456185db85Sdougm 	scf_property_t *prop;
10466185db85Sdougm 	scf_value_t *value;
10476185db85Sdougm 	char *valuestr;
10486185db85Sdougm 	ssize_t vallen;
10496185db85Sdougm 
10506185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
10516185db85Sdougm 	prop = scf_property_create(handle->handle);
10526185db85Sdougm 	value = scf_value_create(handle->handle);
10536185db85Sdougm 	valuestr = malloc(vallen);
105425a68471Sdougm 
105525a68471Sdougm 	if (prop == NULL || value == NULL || vallen == 0 ||
105625a68471Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0)
105725a68471Sdougm 		goto out;
105825a68471Sdougm 
105925a68471Sdougm 	if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
106025a68471Sdougm 		goto out;
106125a68471Sdougm 
106225a68471Sdougm 	/* Found the property so get the value */
10636185db85Sdougm 	if (scf_property_get_value(prop, value) == 0) {
10646185db85Sdougm 		if (scf_value_get_astring(value, valuestr, vallen) > 0) {
10656185db85Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
10666185db85Sdougm 			    NULL);
10676185db85Sdougm 			if (node != NULL) {
10686185db85Sdougm 				xmlSetProp(node, (xmlChar *)"timestamp",
10696185db85Sdougm 				    (xmlChar *)valuestr);
10706185db85Sdougm 				xmlSetProp(node, (xmlChar *)"path",
10716185db85Sdougm 				    (xmlChar *)SA_LEGACY_DFSTAB);
10726185db85Sdougm 			}
10736185db85Sdougm 		}
10746185db85Sdougm 	}
107525a68471Sdougm out:
10766185db85Sdougm 	if (valuestr != NULL)
10776185db85Sdougm 		free(valuestr);
10786185db85Sdougm 	if (value != NULL)
10796185db85Sdougm 		scf_value_destroy(value);
10806185db85Sdougm 	if (prop != NULL)
10816185db85Sdougm 		scf_property_destroy(prop);
10826185db85Sdougm }
10836185db85Sdougm 
10846185db85Sdougm 
10856185db85Sdougm /*
1086*da6c28aaSamw  * sa_get_config(handle, root, doc, sahandle)
10876185db85Sdougm  *
108825a68471Sdougm  * Walk the SMF repository for /network/shares/group and find all the
10896185db85Sdougm  * instances. These become group names.  Then add the XML structure
10906185db85Sdougm  * below the groups based on property groups and properties.
10916185db85Sdougm  */
10926185db85Sdougm int
10931d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
10946185db85Sdougm {
10956185db85Sdougm 	int ret = SA_OK;
10966185db85Sdougm 	scf_instance_t *instance;
10976185db85Sdougm 	scf_iter_t *iter;
10986185db85Sdougm 	char buff[BUFSIZ * 2];
10996185db85Sdougm 
11006185db85Sdougm 	instance = scf_instance_create(handle->handle);
11016185db85Sdougm 	iter = scf_iter_create(handle->handle);
11021d1813a7Sdougm 	if (instance != NULL && iter != NULL) {
11036185db85Sdougm 		if ((ret = scf_iter_service_instances(iter,
11046185db85Sdougm 		    handle->service)) == 0) {
11056185db85Sdougm 			while ((ret = scf_iter_next_instance(iter,
11066185db85Sdougm 			    instance)) > 0) {
11076185db85Sdougm 				if (scf_instance_get_name(instance, buff,
11086185db85Sdougm 				    sizeof (buff)) > 0) {
11096185db85Sdougm 					if (strcmp(buff, "default") == 0)
111025a68471Sdougm 						sa_extract_defaults(root,
111125a68471Sdougm 						    handle, instance);
111225a68471Sdougm 					ret = sa_extract_group(root, handle,
111325a68471Sdougm 					    instance, sahandle);
11146185db85Sdougm 				}
11156185db85Sdougm 			}
11166185db85Sdougm 		}
11176185db85Sdougm 	}
11181d1813a7Sdougm 
111925a68471Sdougm 	/* Always cleanup these */
11206185db85Sdougm 	if (instance != NULL)
11216185db85Sdougm 		scf_instance_destroy(instance);
11226185db85Sdougm 	if (iter != NULL)
11236185db85Sdougm 		scf_iter_destroy(iter);
11246185db85Sdougm 	return (ret);
11256185db85Sdougm }
11266185db85Sdougm 
11276185db85Sdougm /*
11286185db85Sdougm  * sa_get_instance(handle, instance)
11296185db85Sdougm  *
113025a68471Sdougm  * Get the instance of the group service. This is actually the
11316185db85Sdougm  * specific group name. The instance is needed for all property and
11326185db85Sdougm  * control operations.
11336185db85Sdougm  */
11346185db85Sdougm 
11356185db85Sdougm int
11366185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
11376185db85Sdougm {
11386185db85Sdougm 	if (scf_service_get_instance(handle->service, instname,
11396185db85Sdougm 	    handle->instance) != 0) {
11406185db85Sdougm 		return (SA_NO_SUCH_GROUP);
11416185db85Sdougm 	}
11426185db85Sdougm 	return (SA_OK);
11436185db85Sdougm }
11446185db85Sdougm 
11456185db85Sdougm /*
11466185db85Sdougm  * sa_create_instance(handle, instname)
11476185db85Sdougm  *
11486185db85Sdougm  * Create a new SMF service instance. There can only be one with a
11496185db85Sdougm  * given name.
11506185db85Sdougm  */
11516185db85Sdougm 
11526185db85Sdougm int
11536185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
11546185db85Sdougm {
11556185db85Sdougm 	int ret = SA_OK;
11566185db85Sdougm 	char instance[SA_GROUP_INST_LEN];
11576185db85Sdougm 	if (scf_service_add_instance(handle->service, instname,
11586185db85Sdougm 	    handle->instance) != 0) {
11596185db85Sdougm 	/* better error returns need to be added based on real error */
11606185db85Sdougm 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
11616185db85Sdougm 			ret = SA_NO_PERMISSION;
11626185db85Sdougm 		else
11636185db85Sdougm 			ret = SA_DUPLICATE_NAME;
11646185db85Sdougm 	} else {
11656185db85Sdougm 		/* have the service created, so enable it */
11666185db85Sdougm 		(void) snprintf(instance, sizeof (instance), "%s:%s",
11676185db85Sdougm 		    SA_SVC_FMRI_BASE, instname);
11686185db85Sdougm 		(void) smf_enable_instance(instance, 0);
11696185db85Sdougm 	}
11706185db85Sdougm 	return (ret);
11716185db85Sdougm }
11726185db85Sdougm 
11736185db85Sdougm /*
11746185db85Sdougm  * sa_delete_instance(handle, instname)
11756185db85Sdougm  *
11766185db85Sdougm  * When a group goes away, we also remove the service instance.
11776185db85Sdougm  */
11786185db85Sdougm 
11796185db85Sdougm int
11806185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
11816185db85Sdougm {
11826185db85Sdougm 	int ret;
11836185db85Sdougm 
11846185db85Sdougm 	if (strcmp(instname, "default") == 0) {
11856185db85Sdougm 		ret = SA_NO_PERMISSION;
11866185db85Sdougm 	} else {
11876185db85Sdougm 		if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
11886185db85Sdougm 			if (scf_instance_delete(handle->instance) != 0)
11896185db85Sdougm 				/* need better analysis */
11906185db85Sdougm 				ret = SA_NO_PERMISSION;
11916185db85Sdougm 		}
11926185db85Sdougm 	}
11936185db85Sdougm 	return (ret);
11946185db85Sdougm }
11956185db85Sdougm 
11966185db85Sdougm /*
11976185db85Sdougm  * sa_create_pgroup(handle, pgroup)
11986185db85Sdougm  *
11996185db85Sdougm  * create a new property group
12006185db85Sdougm  */
12016185db85Sdougm 
12026185db85Sdougm int
12036185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
12046185db85Sdougm {
12056185db85Sdougm 	int ret = SA_OK;
12066185db85Sdougm 	/*
120725a68471Sdougm 	 * Only create a handle if it doesn't exist. It is ok to exist
12086185db85Sdougm 	 * since the pg handle will be set as a side effect.
12096185db85Sdougm 	 */
121025a68471Sdougm 	if (handle->pg == NULL)
12116185db85Sdougm 		handle->pg = scf_pg_create(handle->handle);
121225a68471Sdougm 
12136185db85Sdougm 	/*
121425a68471Sdougm 	 * If the pgroup exists, we are done. If it doesn't, then we
12156185db85Sdougm 	 * need to actually add one to the service instance.
12166185db85Sdougm 	 */
12176185db85Sdougm 	if (scf_instance_get_pg(handle->instance,
12186185db85Sdougm 	    pgroup, handle->pg) != 0) {
121925a68471Sdougm 		/* Doesn't exist so create one */
12206185db85Sdougm 		if (scf_instance_add_pg(handle->instance, pgroup,
122125a68471Sdougm 		    SCF_GROUP_APPLICATION, 0, handle->pg) != 0) {
12226185db85Sdougm 			switch (scf_error()) {
12236185db85Sdougm 			case SCF_ERROR_PERMISSION_DENIED:
12246185db85Sdougm 				ret = SA_NO_PERMISSION;
12256185db85Sdougm 				break;
12266185db85Sdougm 			default:
12276185db85Sdougm 				ret = SA_SYSTEM_ERR;
12286185db85Sdougm 				break;
12296185db85Sdougm 			}
12306185db85Sdougm 		}
12316185db85Sdougm 	}
12326185db85Sdougm 	return (ret);
12336185db85Sdougm }
12346185db85Sdougm 
12356185db85Sdougm /*
12366185db85Sdougm  * sa_delete_pgroup(handle, pgroup)
12376185db85Sdougm  *
123825a68471Sdougm  * Remove the property group from the current instance of the service,
12396185db85Sdougm  * but only if it actually exists.
12406185db85Sdougm  */
12416185db85Sdougm 
12426185db85Sdougm int
12436185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
12446185db85Sdougm {
12456185db85Sdougm 	int ret = SA_OK;
12466185db85Sdougm 	/*
124725a68471Sdougm 	 * Only delete if it does exist.
12486185db85Sdougm 	 */
124925a68471Sdougm 	if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
12506185db85Sdougm 		/* does exist so delete it */
125125a68471Sdougm 		if (scf_pg_delete(handle->pg) != 0)
12526185db85Sdougm 			ret = SA_SYSTEM_ERR;
12536185db85Sdougm 	} else {
12546185db85Sdougm 		ret = SA_SYSTEM_ERR;
12556185db85Sdougm 	}
12566185db85Sdougm 	if (ret == SA_SYSTEM_ERR &&
12576185db85Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
12586185db85Sdougm 		ret = SA_NO_PERMISSION;
12596185db85Sdougm 	}
12606185db85Sdougm 	return (ret);
12616185db85Sdougm }
12626185db85Sdougm 
12636185db85Sdougm /*
12646185db85Sdougm  * sa_start_transaction(handle, pgroup)
12656185db85Sdougm  *
12666185db85Sdougm  * Start an SMF transaction so we can deal with properties. it would
12676185db85Sdougm  * be nice to not have to expose this, but we have to in order to
12686185db85Sdougm  * optimize.
12696185db85Sdougm  *
12706185db85Sdougm  * Basic model is to hold the transaction in the handle and allow
12716185db85Sdougm  * property adds/deletes/updates to be added then close the
12726185db85Sdougm  * transaction (or abort).  There may eventually be a need to handle
12736185db85Sdougm  * other types of transaction mechanisms but we don't do that now.
12746185db85Sdougm  *
12756185db85Sdougm  * An sa_start_transaction must be followed by either an
12766185db85Sdougm  * sa_end_transaction or sa_abort_transaction before another
12776185db85Sdougm  * sa_start_transaction can be done.
12786185db85Sdougm  */
12796185db85Sdougm 
12806185db85Sdougm int
12816185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
12826185db85Sdougm {
12836185db85Sdougm 	int ret = SA_OK;
12846185db85Sdougm 	/*
128525a68471Sdougm 	 * Lookup the property group and create it if it doesn't already
12866185db85Sdougm 	 * exist.
12876185db85Sdougm 	 */
12886185db85Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
12896185db85Sdougm 		ret = sa_create_pgroup(handle, propgroup);
12906185db85Sdougm 		if (ret == SA_OK) {
12916185db85Sdougm 			handle->trans = scf_transaction_create(handle->handle);
12926185db85Sdougm 			if (handle->trans != NULL) {
129325a68471Sdougm 				if (scf_transaction_start(handle->trans,
129425a68471Sdougm 				    handle->pg) != 0) {
12956185db85Sdougm 					ret = SA_SYSTEM_ERR;
12966185db85Sdougm 				}
12976185db85Sdougm 				if (ret != SA_OK) {
12986185db85Sdougm 					scf_transaction_destroy(handle->trans);
12996185db85Sdougm 					handle->trans = NULL;
13006185db85Sdougm 				}
13016185db85Sdougm 			} else {
13026185db85Sdougm 				ret = SA_SYSTEM_ERR;
13036185db85Sdougm 			}
13046185db85Sdougm 		}
13056185db85Sdougm 	}
13066185db85Sdougm 	if (ret == SA_SYSTEM_ERR &&
13076185db85Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
13086185db85Sdougm 		ret = SA_NO_PERMISSION;
13096185db85Sdougm 	}
13106185db85Sdougm 	return (ret);
13116185db85Sdougm }
13126185db85Sdougm 
13136185db85Sdougm /*
13146185db85Sdougm  * sa_end_transaction(handle)
13156185db85Sdougm  *
13166185db85Sdougm  * Commit the changes that were added to the transaction in the
13176185db85Sdougm  * handle. Do all necessary cleanup.
13186185db85Sdougm  */
13196185db85Sdougm 
13206185db85Sdougm int
13216185db85Sdougm sa_end_transaction(scfutilhandle_t *handle)
13226185db85Sdougm {
13236185db85Sdougm 	int ret = SA_OK;
13246185db85Sdougm 
13256185db85Sdougm 	if (handle->trans == NULL) {
13266185db85Sdougm 		ret = SA_SYSTEM_ERR;
13276185db85Sdougm 	} else {
13286185db85Sdougm 		if (scf_transaction_commit(handle->trans) < 0)
13296185db85Sdougm 			ret = SA_SYSTEM_ERR;
13306185db85Sdougm 		scf_transaction_destroy_children(handle->trans);
13316185db85Sdougm 		scf_transaction_destroy(handle->trans);
13326185db85Sdougm 		handle->trans = NULL;
13336185db85Sdougm 	}
13346185db85Sdougm 	return (ret);
13356185db85Sdougm }
13366185db85Sdougm 
13376185db85Sdougm /*
13386185db85Sdougm  * sa_abort_transaction(handle)
13396185db85Sdougm  *
13406185db85Sdougm  * Abort the changes that were added to the transaction in the
13416185db85Sdougm  * handle. Do all necessary cleanup.
13426185db85Sdougm  */
13436185db85Sdougm 
13446185db85Sdougm void
13456185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle)
13466185db85Sdougm {
13476185db85Sdougm 	if (handle->trans != NULL) {
13486185db85Sdougm 		scf_transaction_reset_all(handle->trans);
13496185db85Sdougm 		scf_transaction_destroy_children(handle->trans);
13506185db85Sdougm 		scf_transaction_destroy(handle->trans);
13516185db85Sdougm 		handle->trans = NULL;
13526185db85Sdougm 	}
13536185db85Sdougm }
13546185db85Sdougm 
13556185db85Sdougm /*
13566185db85Sdougm  * sa_set_property(handle, prop, value)
13576185db85Sdougm  *
135825a68471Sdougm  * Set a property transaction entry into the pending SMF transaction.
13596185db85Sdougm  */
13606185db85Sdougm 
13616185db85Sdougm int
13626185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
13636185db85Sdougm {
13646185db85Sdougm 	int ret = SA_OK;
13656185db85Sdougm 	scf_value_t *value;
13666185db85Sdougm 	scf_transaction_entry_t *entry;
13676185db85Sdougm 	/*
136825a68471Sdougm 	 * Properties must be set in transactions and don't take
13696185db85Sdougm 	 * effect until the transaction has been ended/committed.
13706185db85Sdougm 	 */
13716185db85Sdougm 	value = scf_value_create(handle->handle);
13726185db85Sdougm 	entry = scf_entry_create(handle->handle);
13736185db85Sdougm 	if (value != NULL && entry != NULL) {
13746185db85Sdougm 		if (scf_transaction_property_change(handle->trans, entry,
137525a68471Sdougm 		    propname, SCF_TYPE_ASTRING) == 0 ||
13766185db85Sdougm 		    scf_transaction_property_new(handle->trans, entry,
137725a68471Sdougm 		    propname, SCF_TYPE_ASTRING) == 0) {
13786185db85Sdougm 			if (scf_value_set_astring(value, valstr) == 0) {
13796185db85Sdougm 				if (scf_entry_add_value(entry, value) != 0) {
13806185db85Sdougm 					ret = SA_SYSTEM_ERR;
13816185db85Sdougm 					scf_value_destroy(value);
13826185db85Sdougm 				}
138325a68471Sdougm 				/* The value is in the transaction */
13846185db85Sdougm 				value = NULL;
13856185db85Sdougm 			} else {
138625a68471Sdougm 				/* Value couldn't be constructed */
13876185db85Sdougm 				ret = SA_SYSTEM_ERR;
13886185db85Sdougm 			}
138925a68471Sdougm 			/* The entry is in the transaction */
13906185db85Sdougm 			entry = NULL;
13916185db85Sdougm 		} else {
13926185db85Sdougm 			ret = SA_SYSTEM_ERR;
13936185db85Sdougm 		}
13946185db85Sdougm 	} else {
13956185db85Sdougm 		ret = SA_SYSTEM_ERR;
13966185db85Sdougm 	}
13976185db85Sdougm 	if (ret == SA_SYSTEM_ERR) {
13986185db85Sdougm 		switch (scf_error()) {
13996185db85Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
14006185db85Sdougm 			ret = SA_NO_PERMISSION;
14016185db85Sdougm 			break;
14026185db85Sdougm 		}
14036185db85Sdougm 	}
14046185db85Sdougm 	/*
140525a68471Sdougm 	 * Cleanup if there were any errors that didn't leave these
14066185db85Sdougm 	 * values where they would be cleaned up later.
14076185db85Sdougm 	 */
14086185db85Sdougm 	if (value != NULL)
14096185db85Sdougm 		scf_value_destroy(value);
14106185db85Sdougm 	if (entry != NULL)
14116185db85Sdougm 		scf_entry_destroy(entry);
14126185db85Sdougm 	return (ret);
14136185db85Sdougm }
14146185db85Sdougm 
14156185db85Sdougm /*
1416*da6c28aaSamw  * check_resource(share)
1417*da6c28aaSamw  *
1418*da6c28aaSamw  * Check to see if share has any persistent resources. We don't want
1419*da6c28aaSamw  * to save if they are all transient.
1420*da6c28aaSamw  */
1421*da6c28aaSamw static int
1422*da6c28aaSamw check_resource(sa_share_t share)
1423*da6c28aaSamw {
1424*da6c28aaSamw 	sa_resource_t resource;
1425*da6c28aaSamw 	int ret = B_FALSE;
1426*da6c28aaSamw 
1427*da6c28aaSamw 	for (resource = sa_get_share_resource(share, NULL);
1428*da6c28aaSamw 	    resource != NULL && ret == B_FALSE;
1429*da6c28aaSamw 	    resource = sa_get_next_resource(resource)) {
1430*da6c28aaSamw 		char *type;
1431*da6c28aaSamw 		type = sa_get_resource_attr(resource, "type");
1432*da6c28aaSamw 		if (type != NULL) {
1433*da6c28aaSamw 			if (strcmp(type, "transient") != 0) {
1434*da6c28aaSamw 				ret = B_TRUE;
1435*da6c28aaSamw 			}
1436*da6c28aaSamw 			sa_free_attr_string(type);
1437*da6c28aaSamw 		}
1438*da6c28aaSamw 	}
1439*da6c28aaSamw 	return (ret);
1440*da6c28aaSamw }
1441*da6c28aaSamw 
1442*da6c28aaSamw /*
1443*da6c28aaSamw  * sa_set_resource_property(handle, prop, value)
1444*da6c28aaSamw  *
1445*da6c28aaSamw  * set a property transaction entry into the pending SMF
1446*da6c28aaSamw  * transaction. We don't want to include any transient resources
1447*da6c28aaSamw  */
1448*da6c28aaSamw 
1449*da6c28aaSamw static int
1450*da6c28aaSamw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
1451*da6c28aaSamw {
1452*da6c28aaSamw 	int ret = SA_OK;
1453*da6c28aaSamw 	scf_value_t *value;
1454*da6c28aaSamw 	scf_transaction_entry_t *entry;
1455*da6c28aaSamw 	sa_resource_t resource;
1456*da6c28aaSamw 	char *valstr;
1457*da6c28aaSamw 	char *idstr;
1458*da6c28aaSamw 	char *description;
1459*da6c28aaSamw 	char *propstr = NULL;
1460*da6c28aaSamw 	size_t strsize;
1461*da6c28aaSamw 
1462*da6c28aaSamw 	/* don't bother if no persistent resources */
1463*da6c28aaSamw 	if (check_resource(share) == B_FALSE)
1464*da6c28aaSamw 		return (ret);
1465*da6c28aaSamw 
1466*da6c28aaSamw 	/*
1467*da6c28aaSamw 	 * properties must be set in transactions and don't take
1468*da6c28aaSamw 	 * effect until the transaction has been ended/committed.
1469*da6c28aaSamw 	 */
1470*da6c28aaSamw 	entry = scf_entry_create(handle->handle);
1471*da6c28aaSamw 	if (entry == NULL)
1472*da6c28aaSamw 		return (SA_SYSTEM_ERR);
1473*da6c28aaSamw 
1474*da6c28aaSamw 	if (scf_transaction_property_change(handle->trans, entry,
1475*da6c28aaSamw 	    "resource",	SCF_TYPE_ASTRING) != 0 &&
1476*da6c28aaSamw 	    scf_transaction_property_new(handle->trans, entry,
1477*da6c28aaSamw 	    "resource", SCF_TYPE_ASTRING) != 0) {
1478*da6c28aaSamw 		scf_entry_destroy(entry);
1479*da6c28aaSamw 		return (SA_SYSTEM_ERR);
1480*da6c28aaSamw 
1481*da6c28aaSamw 	}
1482*da6c28aaSamw 	for (resource = sa_get_share_resource(share, NULL);
1483*da6c28aaSamw 	    resource != NULL;
1484*da6c28aaSamw 	    resource = sa_get_next_resource(resource)) {
1485*da6c28aaSamw 		value = scf_value_create(handle->handle);
1486*da6c28aaSamw 		if (value == NULL) {
1487*da6c28aaSamw 			ret = SA_NO_MEMORY;
1488*da6c28aaSamw 			break;
1489*da6c28aaSamw 		}
1490*da6c28aaSamw 			/* Get size of complete string */
1491*da6c28aaSamw 		valstr = sa_get_resource_attr(resource, "name");
1492*da6c28aaSamw 		idstr = sa_get_resource_attr(resource, "id");
1493*da6c28aaSamw 		description = sa_get_resource_description(resource);
1494*da6c28aaSamw 		strsize = (valstr != NULL) ? strlen(valstr) : 0;
1495*da6c28aaSamw 		strsize += (idstr != NULL) ? strlen(idstr) : 0;
1496*da6c28aaSamw 		strsize += (description != NULL) ? strlen(description) : 0;
1497*da6c28aaSamw 		if (strsize > 0) {
1498*da6c28aaSamw 			strsize += 3; /* add nul and ':' */
1499*da6c28aaSamw 			propstr = (char *)malloc(strsize);
1500*da6c28aaSamw 			if (propstr == NULL) {
1501*da6c28aaSamw 				scf_value_destroy(value);
1502*da6c28aaSamw 				ret = SA_NO_MEMORY;
1503*da6c28aaSamw 				goto err;
1504*da6c28aaSamw 			}
1505*da6c28aaSamw 			if (idstr == NULL)
1506*da6c28aaSamw 				(void) snprintf(propstr, strsize, "%s",
1507*da6c28aaSamw 				    valstr ? valstr : "");
1508*da6c28aaSamw 			else
1509*da6c28aaSamw 				(void) snprintf(propstr, strsize, "%s:%s:%s",
1510*da6c28aaSamw 				    idstr ? idstr : "", valstr ? valstr : "",
1511*da6c28aaSamw 				    description ? description : "");
1512*da6c28aaSamw 			if (scf_value_set_astring(value, propstr) != 0) {
1513*da6c28aaSamw 				ret = SA_SYSTEM_ERR;
1514*da6c28aaSamw 				free(propstr);
1515*da6c28aaSamw 				scf_value_destroy(value);
1516*da6c28aaSamw 				break;
1517*da6c28aaSamw 			}
1518*da6c28aaSamw 			if (scf_entry_add_value(entry, value) != 0) {
1519*da6c28aaSamw 				ret = SA_SYSTEM_ERR;
1520*da6c28aaSamw 				free(propstr);
1521*da6c28aaSamw 				scf_value_destroy(value);
1522*da6c28aaSamw 				break;
1523*da6c28aaSamw 			}
1524*da6c28aaSamw 			/* the value is in the transaction */
1525*da6c28aaSamw 			value = NULL;
1526*da6c28aaSamw 			free(propstr);
1527*da6c28aaSamw 		}
1528*da6c28aaSamw err:
1529*da6c28aaSamw 		if (valstr != NULL)
1530*da6c28aaSamw 			sa_free_attr_string(valstr);
1531*da6c28aaSamw 		if (idstr != NULL)
1532*da6c28aaSamw 			sa_free_attr_string(idstr);
1533*da6c28aaSamw 		if (description != NULL)
1534*da6c28aaSamw 			sa_free_share_description(description);
1535*da6c28aaSamw 	}
1536*da6c28aaSamw 	/* the entry is in the transaction */
1537*da6c28aaSamw 	entry = NULL;
1538*da6c28aaSamw 
1539*da6c28aaSamw 	if (ret == SA_SYSTEM_ERR) {
1540*da6c28aaSamw 		switch (scf_error()) {
1541*da6c28aaSamw 		case SCF_ERROR_PERMISSION_DENIED:
1542*da6c28aaSamw 			ret = SA_NO_PERMISSION;
1543*da6c28aaSamw 			break;
1544*da6c28aaSamw 		}
1545*da6c28aaSamw 	}
1546*da6c28aaSamw 	/*
1547*da6c28aaSamw 	 * cleanup if there were any errors that didn't leave
1548*da6c28aaSamw 	 * these values where they would be cleaned up later.
1549*da6c28aaSamw 	 */
1550*da6c28aaSamw 	if (entry != NULL)
1551*da6c28aaSamw 		scf_entry_destroy(entry);
1552*da6c28aaSamw 
1553*da6c28aaSamw 	return (ret);
1554*da6c28aaSamw }
1555*da6c28aaSamw 
1556*da6c28aaSamw /*
15576185db85Sdougm  * sa_commit_share(handle, group, share)
15586185db85Sdougm  *
155925a68471Sdougm  *	Commit this share to the repository.
15606185db85Sdougm  *	properties are added if they exist but can be added later.
15616185db85Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
15626185db85Sdougm  */
15636185db85Sdougm int
15646185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
15656185db85Sdougm {
15666185db85Sdougm 	int ret = SA_OK;
15676185db85Sdougm 	char *groupname;
15686185db85Sdougm 	char *name;
15696185db85Sdougm 	char *description;
15706185db85Sdougm 	char *sharename;
15716185db85Sdougm 	ssize_t proplen;
15726185db85Sdougm 	char *propstring;
15736185db85Sdougm 
15746185db85Sdougm 	/*
157525a68471Sdougm 	 * Don't commit in the zfs group. We do commit legacy
15766185db85Sdougm 	 * (default) and all other groups/shares. ZFS is handled
15776185db85Sdougm 	 * through the ZFS configuration rather than SMF.
15786185db85Sdougm 	 */
15796185db85Sdougm 
15806185db85Sdougm 	groupname = sa_get_group_attr(group, "name");
15816185db85Sdougm 	if (groupname != NULL) {
15826185db85Sdougm 		if (strcmp(groupname, "zfs") == 0) {
15836185db85Sdougm 			/*
158425a68471Sdougm 			 * Adding to the ZFS group will result in the sharenfs
15856185db85Sdougm 			 * property being set but we don't want to do anything
15866185db85Sdougm 			 * SMF related at this point.
15876185db85Sdougm 			 */
15886185db85Sdougm 			sa_free_attr_string(groupname);
15896185db85Sdougm 			return (ret);
15906185db85Sdougm 		}
15916185db85Sdougm 	}
15926185db85Sdougm 
15936185db85Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
15946185db85Sdougm 	propstring = malloc(proplen);
15956185db85Sdougm 	if (propstring == NULL)
15966185db85Sdougm 		ret = SA_NO_MEMORY;
15976185db85Sdougm 
15986185db85Sdougm 	if (groupname != NULL && ret == SA_OK) {
15996185db85Sdougm 		ret = sa_get_instance(handle, groupname);
16006185db85Sdougm 		sa_free_attr_string(groupname);
16016185db85Sdougm 		groupname = NULL;
16026185db85Sdougm 		sharename = sa_get_share_attr(share, "id");
16036185db85Sdougm 		if (sharename == NULL) {
16046185db85Sdougm 			/* slipped by */
16056185db85Sdougm 			char shname[SA_SHARE_UUID_BUFLEN];
16066185db85Sdougm 			generate_unique_sharename(shname);
16076185db85Sdougm 			xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
16086185db85Sdougm 			    (xmlChar *)shname);
16096185db85Sdougm 			sharename = strdup(shname);
16106185db85Sdougm 		}
16116185db85Sdougm 		if (sharename != NULL) {
1612f345c0beSdougm 			sigset_t old, new;
16136185db85Sdougm 			/*
161425a68471Sdougm 			 * Have a share name allocated so create a pgroup for
1615f345c0beSdougm 			 * it. It may already exist, but that is OK.  In order
1616f345c0beSdougm 			 * to avoid creating a share pgroup that doesn't have
1617f345c0beSdougm 			 * a path property, block signals around the critical
1618f345c0beSdougm 			 * region of creating the share pgroup and props.
16196185db85Sdougm 			 */
1620f345c0beSdougm 			(void) sigprocmask(SIG_BLOCK, NULL, &new);
1621f345c0beSdougm 			(void) sigaddset(&new, SIGHUP);
1622f345c0beSdougm 			(void) sigaddset(&new, SIGINT);
1623f345c0beSdougm 			(void) sigaddset(&new, SIGQUIT);
1624f345c0beSdougm 			(void) sigaddset(&new, SIGTSTP);
1625f345c0beSdougm 			(void) sigprocmask(SIG_SETMASK, &new, &old);
1626f345c0beSdougm 
16276185db85Sdougm 			ret = sa_create_pgroup(handle, sharename);
16286185db85Sdougm 			if (ret == SA_OK) {
16296185db85Sdougm 				/*
163025a68471Sdougm 				 * Now start the transaction for the
16316185db85Sdougm 				 * properties that define this share. They may
16326185db85Sdougm 				 * exist so attempt to update before create.
16336185db85Sdougm 				 */
16346185db85Sdougm 				ret = sa_start_transaction(handle, sharename);
16356185db85Sdougm 			}
16366185db85Sdougm 			if (ret == SA_OK) {
16376185db85Sdougm 				name = sa_get_share_attr(share, "path");
16386185db85Sdougm 				if (name != NULL) {
163925a68471Sdougm 					/*
164025a68471Sdougm 					 * There needs to be a path
164125a68471Sdougm 					 * for a share to exist.
164225a68471Sdougm 					 */
164325a68471Sdougm 					ret = sa_set_property(handle, "path",
164425a68471Sdougm 					    name);
16456185db85Sdougm 					sa_free_attr_string(name);
16466185db85Sdougm 				} else {
16476185db85Sdougm 					ret = SA_NO_MEMORY;
16486185db85Sdougm 				}
16496185db85Sdougm 			}
16506185db85Sdougm 			if (ret == SA_OK) {
1651*da6c28aaSamw 				name = sa_get_share_attr(share, "drive-letter");
1652*da6c28aaSamw 				if (name != NULL) {
1653*da6c28aaSamw 					/* A drive letter may exist for SMB */
165425a68471Sdougm 					ret = sa_set_property(handle,
1655*da6c28aaSamw 					    "drive-letter", name);
1656*da6c28aaSamw 					sa_free_attr_string(name);
16576185db85Sdougm 				}
16586185db85Sdougm 			}
16596185db85Sdougm 			if (ret == SA_OK) {
1660*da6c28aaSamw 				name = sa_get_share_attr(share, "exclude");
1661*da6c28aaSamw 				if (name != NULL) {
1662*da6c28aaSamw 					/*
1663*da6c28aaSamw 					 * In special cases need to
1664*da6c28aaSamw 					 * exclude proto enable.
1665*da6c28aaSamw 					 */
1666*da6c28aaSamw 					ret = sa_set_property(handle,
1667*da6c28aaSamw 					    "exclude", name);
1668*da6c28aaSamw 					sa_free_attr_string(name);
1669*da6c28aaSamw 				}
1670*da6c28aaSamw 			}
1671*da6c28aaSamw 			if (ret == SA_OK) {
1672*da6c28aaSamw 				/*
1673*da6c28aaSamw 				 * If there are resource names, bundle them up
1674*da6c28aaSamw 				 * and save appropriately.
1675*da6c28aaSamw 				 */
1676*da6c28aaSamw 				ret = sa_set_resource_property(handle, share);
1677*da6c28aaSamw 			}
1678*da6c28aaSamw 
1679*da6c28aaSamw 			if (ret == SA_OK) {
16806185db85Sdougm 				description = sa_get_share_description(share);
16816185db85Sdougm 				if (description != NULL) {
168225a68471Sdougm 					ret = sa_set_property(handle,
168325a68471Sdougm 					    "description",
16846185db85Sdougm 					    description);
16856185db85Sdougm 					sa_free_share_description(description);
16866185db85Sdougm 				}
16876185db85Sdougm 			}
168825a68471Sdougm 			/* Make sure we cleanup the transaction */
16896185db85Sdougm 			if (ret == SA_OK) {
16906185db85Sdougm 				ret = sa_end_transaction(handle);
16916185db85Sdougm 			} else {
16926185db85Sdougm 				sa_abort_transaction(handle);
16936185db85Sdougm 			}
1694f345c0beSdougm 
1695f345c0beSdougm 			(void) sigprocmask(SIG_SETMASK, &old, NULL);
1696f345c0beSdougm 
16976185db85Sdougm 			free(sharename);
16986185db85Sdougm 		}
16996185db85Sdougm 	}
17006185db85Sdougm 	if (ret == SA_SYSTEM_ERR) {
17016185db85Sdougm 		int err = scf_error();
17026185db85Sdougm 		if (err == SCF_ERROR_PERMISSION_DENIED)
17036185db85Sdougm 			ret = SA_NO_PERMISSION;
17046185db85Sdougm 	}
17056185db85Sdougm 	if (propstring != NULL)
17066185db85Sdougm 		free(propstring);
17076185db85Sdougm 	if (groupname != NULL)
17086185db85Sdougm 		sa_free_attr_string(groupname);
17096185db85Sdougm 
17106185db85Sdougm 	return (ret);
17116185db85Sdougm }
17126185db85Sdougm 
17136185db85Sdougm /*
1714*da6c28aaSamw  * remove_resources(handle, share, shareid)
1715*da6c28aaSamw  *
1716*da6c28aaSamw  * If the share has resources, remove all of them and their
1717*da6c28aaSamw  * optionsets.
1718*da6c28aaSamw  */
1719*da6c28aaSamw static int
1720*da6c28aaSamw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
1721*da6c28aaSamw {
1722*da6c28aaSamw 	sa_resource_t resource;
1723*da6c28aaSamw 	sa_optionset_t opt;
1724*da6c28aaSamw 	char *proto;
1725*da6c28aaSamw 	char *id;
1726*da6c28aaSamw 	ssize_t proplen;
1727*da6c28aaSamw 	char *propstring;
1728*da6c28aaSamw 	int ret = SA_OK;
1729*da6c28aaSamw 
1730*da6c28aaSamw 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1731*da6c28aaSamw 	propstring = malloc(proplen);
1732*da6c28aaSamw 	if (propstring == NULL)
1733*da6c28aaSamw 		return (SA_NO_MEMORY);
1734*da6c28aaSamw 
1735*da6c28aaSamw 	for (resource = sa_get_share_resource(share, NULL);
1736*da6c28aaSamw 	    resource != NULL; resource = sa_get_next_resource(resource)) {
1737*da6c28aaSamw 		id = sa_get_resource_attr(resource, "id");
1738*da6c28aaSamw 		if (id == NULL)
1739*da6c28aaSamw 			continue;
1740*da6c28aaSamw 		for (opt = sa_get_optionset(resource, NULL);
1741*da6c28aaSamw 		    opt != NULL; opt = sa_get_next_optionset(resource)) {
1742*da6c28aaSamw 			proto = sa_get_optionset_attr(opt, "type");
1743*da6c28aaSamw 			if (proto != NULL) {
1744*da6c28aaSamw 				(void) snprintf(propstring, proplen,
1745*da6c28aaSamw 				    "%s_%s_%s", shareid, proto, id);
1746*da6c28aaSamw 				ret = sa_delete_pgroup(handle, propstring);
1747*da6c28aaSamw 				sa_free_attr_string(proto);
1748*da6c28aaSamw 			}
1749*da6c28aaSamw 		}
1750*da6c28aaSamw 		sa_free_attr_string(id);
1751*da6c28aaSamw 	}
1752*da6c28aaSamw 	free(propstring);
1753*da6c28aaSamw 	return (ret);
1754*da6c28aaSamw }
1755*da6c28aaSamw 
1756*da6c28aaSamw /*
17576185db85Sdougm  * sa_delete_share(handle, group, share)
17586185db85Sdougm  *
175925a68471Sdougm  * Remove the specified share from the group (and service instance).
17606185db85Sdougm  */
17616185db85Sdougm 
17626185db85Sdougm int
17636185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
17646185db85Sdougm {
17656185db85Sdougm 	int ret = SA_OK;
17666185db85Sdougm 	char *groupname = NULL;
17676185db85Sdougm 	char *shareid = NULL;
17686185db85Sdougm 	sa_optionset_t opt;
17696185db85Sdougm 	sa_security_t sec;
17706185db85Sdougm 	ssize_t proplen;
17716185db85Sdougm 	char *propstring;
17726185db85Sdougm 
17736185db85Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
17746185db85Sdougm 	propstring = malloc(proplen);
17756185db85Sdougm 	if (propstring == NULL)
17766185db85Sdougm 		ret = SA_NO_MEMORY;
17776185db85Sdougm 
17786185db85Sdougm 	if (ret == SA_OK) {
17796185db85Sdougm 		groupname = sa_get_group_attr(group, "name");
17806185db85Sdougm 		shareid = sa_get_share_attr(share, "id");
178125a68471Sdougm 		if (groupname == NULL || shareid == NULL) {
178225a68471Sdougm 			ret = SA_CONFIG_ERR;
178325a68471Sdougm 			goto out;
178425a68471Sdougm 		}
17856185db85Sdougm 		ret = sa_get_instance(handle, groupname);
17866185db85Sdougm 		if (ret == SA_OK) {
1787*da6c28aaSamw 			/* If a share has resources, remove them */
1788*da6c28aaSamw 			ret = remove_resources(handle, share, shareid);
178925a68471Sdougm 			/* If a share has properties, remove them */
17906185db85Sdougm 			ret = sa_delete_pgroup(handle, shareid);
179125a68471Sdougm 			for (opt = sa_get_optionset(share, NULL);
179225a68471Sdougm 			    opt != NULL;
17936185db85Sdougm 			    opt = sa_get_next_optionset(opt)) {
17946185db85Sdougm 				char *proto;
17956185db85Sdougm 				proto = sa_get_optionset_attr(opt, "type");
17966185db85Sdougm 				if (proto != NULL) {
179725a68471Sdougm 					(void) snprintf(propstring,
179825a68471Sdougm 					    proplen, "%s_%s", shareid,
179925a68471Sdougm 					    proto);
180025a68471Sdougm 					ret = sa_delete_pgroup(handle,
180125a68471Sdougm 					    propstring);
18026185db85Sdougm 					sa_free_attr_string(proto);
18036185db85Sdougm 				} else {
18046185db85Sdougm 					ret = SA_NO_MEMORY;
18056185db85Sdougm 				}
18066185db85Sdougm 			}
18076185db85Sdougm 			/*
180825a68471Sdougm 			 * If a share has security/negotiable
18096185db85Sdougm 			 * properties, remove them.
18106185db85Sdougm 			 */
181125a68471Sdougm 			for (sec = sa_get_security(share, NULL, NULL);
181225a68471Sdougm 			    sec != NULL;
18136185db85Sdougm 			    sec = sa_get_next_security(sec)) {
18146185db85Sdougm 				char *proto;
18156185db85Sdougm 				char *sectype;
18166185db85Sdougm 				proto = sa_get_security_attr(sec, "type");
18176185db85Sdougm 				sectype = sa_get_security_attr(sec, "sectype");
18186185db85Sdougm 				if (proto != NULL && sectype != NULL) {
181925a68471Sdougm 					(void) snprintf(propstring, proplen,
182025a68471Sdougm 					    "%s_%s_%s", shareid,  proto,
182125a68471Sdougm 					    sectype);
182225a68471Sdougm 					ret = sa_delete_pgroup(handle,
182325a68471Sdougm 					    propstring);
18246185db85Sdougm 				} else {
18256185db85Sdougm 					ret = SA_NO_MEMORY;
18266185db85Sdougm 				}
18276185db85Sdougm 				if (proto != NULL)
18286185db85Sdougm 					sa_free_attr_string(proto);
18296185db85Sdougm 				if (sectype != NULL)
18306185db85Sdougm 					sa_free_attr_string(sectype);
18316185db85Sdougm 			}
18326185db85Sdougm 		}
18336185db85Sdougm 	}
183425a68471Sdougm out:
18356185db85Sdougm 	if (groupname != NULL)
18366185db85Sdougm 		sa_free_attr_string(groupname);
18376185db85Sdougm 	if (shareid != NULL)
18386185db85Sdougm 		sa_free_attr_string(shareid);
18396185db85Sdougm 	if (propstring != NULL)
18406185db85Sdougm 		free(propstring);
18416185db85Sdougm 
18426185db85Sdougm 	return (ret);
18436185db85Sdougm }
1844