13034Sdougm /*
23034Sdougm  * CDDL HEADER START
33034Sdougm  *
43034Sdougm  * The contents of this file are subject to the terms of the
53034Sdougm  * Common Development and Distribution License (the "License").
63034Sdougm  * You may not use this file except in compliance with the License.
73034Sdougm  *
83034Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm  * or http://www.opensolaris.org/os/licensing.
103034Sdougm  * See the License for the specific language governing permissions
113034Sdougm  * and limitations under the License.
123034Sdougm  *
133034Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm  * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm  *
193034Sdougm  * CDDL HEADER END
203034Sdougm  */
213034Sdougm 
223034Sdougm /*
233348Sdougm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
243034Sdougm  * Use is subject to license terms.
253034Sdougm  */
263034Sdougm 
273034Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
283034Sdougm 
293034Sdougm /* helper functions for using libscf with sharemgr */
303034Sdougm 
313034Sdougm #include <libscf.h>
323034Sdougm #include <libxml/parser.h>
333034Sdougm #include <libxml/tree.h>
343034Sdougm #include "libshare.h"
353034Sdougm #include "libshare_impl.h"
363034Sdougm #include "scfutil.h"
373034Sdougm #include <string.h>
383034Sdougm #include <errno.h>
393034Sdougm #include <uuid/uuid.h>
403034Sdougm #include <sys/param.h>
413348Sdougm #include <signal.h>
423034Sdougm 
433034Sdougm ssize_t scf_max_name_len;
443034Sdougm extern struct sa_proto_plugin *sap_proto_list;
453910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
463034Sdougm 
473034Sdougm /*
483034Sdougm  * The SMF facility uses some properties that must exist. We want to
493034Sdougm  * skip over these when processing protocol options.
503034Sdougm  */
513034Sdougm static char *skip_props[] = {
523034Sdougm 	"modify_authorization",
533034Sdougm 	"action_authorization",
543034Sdougm 	"value_authorization",
553034Sdougm 	NULL
563034Sdougm };
573034Sdougm 
583034Sdougm /*
593034Sdougm  * sa_scf_fini(handle)
603034Sdougm  *
61*4653Sdougm  * Must be called when done. Called with the handle allocated in
623034Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
633034Sdougm  * still in use. Called by sa_fini().
643034Sdougm  */
653034Sdougm 
663034Sdougm void
673034Sdougm sa_scf_fini(scfutilhandle_t *handle)
683034Sdougm {
693034Sdougm 	if (handle != NULL) {
70*4653Sdougm 		int unbind = 0;
71*4653Sdougm 		if (handle->scope != NULL) {
72*4653Sdougm 			unbind = 1;
73*4653Sdougm 			scf_scope_destroy(handle->scope);
74*4653Sdougm 		}
75*4653Sdougm 		if (handle->instance != NULL)
76*4653Sdougm 			scf_instance_destroy(handle->instance);
77*4653Sdougm 		if (handle->service != NULL)
78*4653Sdougm 			scf_service_destroy(handle->service);
79*4653Sdougm 		if (handle->pg != NULL)
80*4653Sdougm 			scf_pg_destroy(handle->pg);
81*4653Sdougm 		if (handle->handle != NULL) {
82*4653Sdougm 			handle->scf_state = SCH_STATE_UNINIT;
83*4653Sdougm 			if (unbind)
84*4653Sdougm 				(void) scf_handle_unbind(handle->handle);
85*4653Sdougm 			scf_handle_destroy(handle->handle);
86*4653Sdougm 		}
87*4653Sdougm 		free(handle);
883034Sdougm 	}
893034Sdougm }
903034Sdougm 
913034Sdougm /*
923034Sdougm  * sa_scf_init()
933034Sdougm  *
94*4653Sdougm  * Must be called before using any of the SCF functions. Called by
953034Sdougm  * sa_init() during the API setup.
963034Sdougm  */
973034Sdougm 
983034Sdougm scfutilhandle_t *
993910Sdougm sa_scf_init(sa_handle_impl_t ihandle)
1003034Sdougm {
1013034Sdougm 	scfutilhandle_t *handle;
1023034Sdougm 
1033034Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1043034Sdougm 	if (scf_max_name_len <= 0)
105*4653Sdougm 		scf_max_name_len = SA_MAX_NAME_LEN + 1;
1063034Sdougm 
1073034Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
108*4653Sdougm 	if (handle == NULL)
109*4653Sdougm 		return (handle);
1104345Sdougm 
111*4653Sdougm 	ihandle->scfhandle = handle;
112*4653Sdougm 	handle->scf_state = SCH_STATE_INITIALIZING;
113*4653Sdougm 	handle->handle = scf_handle_create(SCF_VERSION);
114*4653Sdougm 	if (handle->handle == NULL) {
1153034Sdougm 		free(handle);
1163034Sdougm 		handle = NULL;
1173034Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
118*4653Sdougm 		    scf_strerror(scf_error()));
119*4653Sdougm 		return (handle);
1203034Sdougm 	}
121*4653Sdougm 	if (scf_handle_bind(handle->handle) != 0)
122*4653Sdougm 		goto err;
123*4653Sdougm 
124*4653Sdougm 	handle->scope = scf_scope_create(handle->handle);
125*4653Sdougm 	handle->service = scf_service_create(handle->handle);
126*4653Sdougm 	handle->pg = scf_pg_create(handle->handle);
127*4653Sdougm 
128*4653Sdougm 	/* Make sure we have sufficient SMF running */
129*4653Sdougm 	handle->instance = scf_instance_create(handle->handle);
130*4653Sdougm 	if (handle->scope == NULL || handle->service == NULL ||
131*4653Sdougm 	    handle->pg == NULL || handle->instance == NULL)
132*4653Sdougm 		goto err;
133*4653Sdougm 	if (scf_handle_get_scope(handle->handle,
134*4653Sdougm 	    SCF_SCOPE_LOCAL, handle->scope) != 0)
135*4653Sdougm 		goto err;
136*4653Sdougm 	if (scf_scope_get_service(handle->scope,
137*4653Sdougm 	    SA_GROUP_SVC_NAME, handle->service) != 0)
138*4653Sdougm 		goto err;
139*4653Sdougm 
140*4653Sdougm 	handle->scf_state = SCH_STATE_INIT;
141*4653Sdougm 	if (sa_get_instance(handle, "default") != SA_OK) {
142*4653Sdougm 		char **protolist;
143*4653Sdougm 		int numprotos, i;
144*4653Sdougm 		sa_group_t defgrp;
145*4653Sdougm 		defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
146*4653Sdougm 		if (defgrp != NULL) {
147*4653Sdougm 			numprotos = sa_get_protocols(
148*4653Sdougm 			    &protolist);
149*4653Sdougm 			for (i = 0; i < numprotos; i++)
150*4653Sdougm 				(void) sa_create_optionset(defgrp,
151*4653Sdougm 				    protolist[i]);
152*4653Sdougm 			if (protolist != NULL)
153*4653Sdougm 				free(protolist);
154*4653Sdougm 		}
155*4653Sdougm 	}
156*4653Sdougm 
1573034Sdougm 	return (handle);
1583034Sdougm 
159*4653Sdougm 	/* Error handling/unwinding */
1603034Sdougm err:
1613034Sdougm 	(void) sa_scf_fini(handle);
1623034Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
163*4653Sdougm 	    scf_strerror(scf_error()));
1643034Sdougm 	return (NULL);
1653034Sdougm }
1663034Sdougm 
1673034Sdougm /*
1683034Sdougm  * get_scf_limit(name)
1693034Sdougm  *
1703034Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
1713034Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
1723034Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
1733034Sdougm  * (1024) so we have a reasonable default buffer size.
1743034Sdougm  */
1753034Sdougm static ssize_t
1763034Sdougm get_scf_limit(uint32_t name)
1773034Sdougm {
1783034Sdougm 	ssize_t vallen;
1793034Sdougm 
1803034Sdougm 	vallen = scf_limit(name);
1813034Sdougm 	if (vallen == (ssize_t)-1)
182*4653Sdougm 		vallen = MAXPATHLEN;
1833034Sdougm 	return (vallen);
1843034Sdougm }
1853034Sdougm 
1863034Sdougm /*
1873034Sdougm  * skip_property(name)
1883034Sdougm  *
189*4653Sdougm  * Internal function to check to see if a property is an SMF magic
1903034Sdougm  * property that needs to be skipped.
1913034Sdougm  */
1923034Sdougm static int
1933034Sdougm skip_property(char *name)
1943034Sdougm {
1953034Sdougm 	int i;
1963034Sdougm 
1973034Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
198*4653Sdougm 		if (strcmp(name, skip_props[i]) == 0)
1993034Sdougm 		return (1);
2003034Sdougm 	return (0);
2013034Sdougm }
2023034Sdougm 
2033034Sdougm /*
2043034Sdougm  * generate_unique_sharename(sharename)
2053034Sdougm  *
2063034Sdougm  * Shares are represented in SMF as property groups. Due to share
2073034Sdougm  * paths containing characters that are not allowed in SMF names and
2083034Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
2093034Sdougm  */
2103034Sdougm 
2113034Sdougm static void
2123034Sdougm generate_unique_sharename(char *sharename)
2133034Sdougm {
2143034Sdougm 	uuid_t uuid;
2153034Sdougm 
2163034Sdougm 	uuid_generate(uuid);
2173034Sdougm 	(void) strcpy(sharename, "S-");
2183034Sdougm 	uuid_unparse(uuid, sharename + 2);
2193034Sdougm }
2203034Sdougm 
2213034Sdougm /*
2223034Sdougm  * valid_protocol(proto)
2233034Sdougm  *
224*4653Sdougm  * Check to see if the specified protocol is a valid one for the
2253034Sdougm  * general sharemgr facility. We determine this by checking which
2263034Sdougm  * plugin protocols were found.
2273034Sdougm  */
2283034Sdougm 
2293034Sdougm static int
2303034Sdougm valid_protocol(char *proto)
2313034Sdougm {
2323034Sdougm 	struct sa_proto_plugin *plugin;
2333034Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
2343034Sdougm 	    plugin = plugin->plugin_next)
235*4653Sdougm 		if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
236*4653Sdougm 			return (1);
2373034Sdougm 	return (0);
2383034Sdougm }
2393034Sdougm 
2403034Sdougm /*
2413034Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2423034Sdougm  *
243*4653Sdougm  * Extract the name property group and create the specified type of
2443034Sdougm  * node on the provided group.  type will be optionset or security.
2453034Sdougm  */
2463034Sdougm 
2473034Sdougm static int
2483034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2493034Sdougm 			scf_propertygroup_t *pg,
2503034Sdougm 			char *nodetype, char *proto, char *sectype)
2513034Sdougm {
2523034Sdougm 	xmlNodePtr node;
2533034Sdougm 	scf_iter_t *iter;
2543034Sdougm 	scf_property_t *prop;
2553034Sdougm 	scf_value_t *value;
2563034Sdougm 	char *name;
2573034Sdougm 	char *valuestr;
2583034Sdougm 	ssize_t vallen;
2593034Sdougm 	int ret = SA_OK;
2603034Sdougm 
2613034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2623034Sdougm 
2633034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
264*4653Sdougm 	if (node == NULL)
265*4653Sdougm 		return (ret);
266*4653Sdougm 
267*4653Sdougm 	if (proto != NULL)
2683034Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
269*4653Sdougm 	if (sectype != NULL)
2703034Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
271*4653Sdougm 	/*
272*4653Sdougm 	 * Have node to work with so iterate over the properties
273*4653Sdougm 	 * in the pg and create option sub nodes.
274*4653Sdougm 	 */
275*4653Sdougm 	iter = scf_iter_create(handle->handle);
276*4653Sdougm 	value = scf_value_create(handle->handle);
277*4653Sdougm 	prop = scf_property_create(handle->handle);
278*4653Sdougm 	name = malloc(scf_max_name_len);
279*4653Sdougm 	valuestr = malloc(vallen);
280*4653Sdougm 	/*
281*4653Sdougm 	 * Want to iterate through the properties and add them
282*4653Sdougm 	 * to the base optionset.
283*4653Sdougm 	 */
284*4653Sdougm 	if (iter == NULL || value == NULL || prop == NULL ||
285*4653Sdougm 	    valuestr == NULL || name == NULL) {
286*4653Sdougm 		ret = SA_NO_MEMORY;
287*4653Sdougm 		goto out;
288*4653Sdougm 	}
289*4653Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
290*4653Sdougm 		/* Now iterate the properties in the group */
291*4653Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
292*4653Sdougm 			/* have a property */
293*4653Sdougm 			if (scf_property_get_name(prop, name,
294*4653Sdougm 			    scf_max_name_len) > 0) {
295*4653Sdougm 				sa_property_t saprop;
296*4653Sdougm 				/* Some properties are part of the framework */
2973034Sdougm 				if (skip_property(name))
298*4653Sdougm 					continue;
299*4653Sdougm 				if (scf_property_get_value(prop, value) != 0)
300*4653Sdougm 					continue;
301*4653Sdougm 				if (scf_value_get_astring(value, valuestr,
302*4653Sdougm 				    vallen) < 0)
303*4653Sdougm 					continue;
304*4653Sdougm 				saprop = sa_create_property(name, valuestr);
305*4653Sdougm 				if (saprop != NULL) {
3063034Sdougm 					/*
307*4653Sdougm 					 * Since in SMF, don't
3083034Sdougm 					 * recurse. Use xmlAddChild
3093034Sdougm 					 * directly, instead.
3103034Sdougm 					 */
311*4653Sdougm 					xmlAddChild(node,
312*4653Sdougm 					    (xmlNodePtr) saprop);
3133034Sdougm 				}
3143034Sdougm 			}
3153034Sdougm 		}
3163034Sdougm 	}
317*4653Sdougm out:
318*4653Sdougm 	/* cleanup to avoid memory leaks */
319*4653Sdougm 	if (value != NULL)
320*4653Sdougm 		scf_value_destroy(value);
321*4653Sdougm 	if (iter != NULL)
322*4653Sdougm 		scf_iter_destroy(iter);
323*4653Sdougm 	if (prop != NULL)
324*4653Sdougm 		scf_property_destroy(prop);
325*4653Sdougm 	if (name != NULL)
326*4653Sdougm 		free(name);
327*4653Sdougm 	if (valuestr != NULL)
328*4653Sdougm 		free(valuestr);
329*4653Sdougm 
3303034Sdougm 	return (ret);
3313034Sdougm }
3323034Sdougm 
3333034Sdougm /*
3343034Sdougm  * sa_extract_attrs(root, handle, instance)
3353034Sdougm  *
336*4653Sdougm  * Local function to extract the actual attributes/properties from the
3373034Sdougm  * property group of the service instance. These are the well known
3383034Sdougm  * attributes of "state" and "zfs". If additional attributes are
3393034Sdougm  * added, they should be added here.
3403034Sdougm  */
3413034Sdougm 
3423034Sdougm static void
3433034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3443034Sdougm 		    scf_instance_t *instance)
3453034Sdougm {
3463034Sdougm 	scf_property_t *prop;
3473034Sdougm 	scf_value_t *value;
3483034Sdougm 	char *valuestr;
3493034Sdougm 	ssize_t vallen;
3503034Sdougm 
3513034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3523034Sdougm 	prop = scf_property_create(handle->handle);
3533034Sdougm 	value = scf_value_create(handle->handle);
3543034Sdougm 	valuestr = malloc(vallen);
355*4653Sdougm 	if (prop == NULL || value == NULL || valuestr == NULL ||
356*4653Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
357*4653Sdougm 		goto out;
358*4653Sdougm 	}
359*4653Sdougm 	/*
360*4653Sdougm 	 * Have a property group with desired name so now get
361*4653Sdougm 	 * the known attributes.
362*4653Sdougm 	 */
363*4653Sdougm 	if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
364*4653Sdougm 		/* Found the property so get the value */
3653034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
366*4653Sdougm 			if (scf_value_get_astring(value, valuestr,
367*4653Sdougm 			    vallen) >= 0) {
368*4653Sdougm 				xmlSetProp(root, (xmlChar *)"state",
3693034Sdougm 				    (xmlChar *)valuestr);
370*4653Sdougm 			}
3713034Sdougm 		}
372*4653Sdougm 	}
373*4653Sdougm 	if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
374*4653Sdougm 		/* Found the property so get the value */
3753034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
376*4653Sdougm 			if (scf_value_get_astring(value, valuestr,
377*4653Sdougm 			    vallen) > 0) {
378*4653Sdougm 				xmlSetProp(root, (xmlChar *)"zfs",
3793034Sdougm 				    (xmlChar *)valuestr);
380*4653Sdougm 			}
3813034Sdougm 		}
3823034Sdougm 	}
383*4653Sdougm out:
3843034Sdougm 	if (valuestr != NULL)
385*4653Sdougm 		free(valuestr);
3863034Sdougm 	if (value != NULL)
387*4653Sdougm 		scf_value_destroy(value);
3883034Sdougm 	if (prop != NULL)
389*4653Sdougm 		scf_property_destroy(prop);
3903034Sdougm }
3913034Sdougm 
3923034Sdougm /*
393*4653Sdougm  * List of known share attributes.
3943034Sdougm  */
3953034Sdougm 
3963034Sdougm static char *share_attr[] = {
3973034Sdougm 	"path",
3983034Sdougm 	"id",
3993034Sdougm 	"resource",
4003034Sdougm 	NULL,
4013034Sdougm };
4023034Sdougm 
4033034Sdougm static int
4043034Sdougm is_share_attr(char *name)
4053034Sdougm {
4063034Sdougm 	int i;
4073034Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
408*4653Sdougm 		if (strcmp(name, share_attr[i]) == 0)
409*4653Sdougm 			return (1);
4103034Sdougm 	return (0);
4113034Sdougm }
4123034Sdougm 
4133034Sdougm /*
4143034Sdougm  * sa_share_from_pgroup
4153034Sdougm  *
416*4653Sdougm  * Extract the share definition from the share property group. We do
4173034Sdougm  * some sanity checking to avoid bad data.
4183034Sdougm  *
4193034Sdougm  * Since this is only constructing the internal data structures, we
4203034Sdougm  * don't use the sa_* functions most of the time.
4213034Sdougm  */
4223034Sdougm void
4233034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4243034Sdougm 			scf_propertygroup_t *pg, char *id)
4253034Sdougm {
4263034Sdougm 	xmlNodePtr node;
4273034Sdougm 	char *name;
4283034Sdougm 	scf_iter_t *iter;
4293034Sdougm 	scf_property_t *prop;
4303034Sdougm 	scf_value_t *value;
4313034Sdougm 	ssize_t vallen;
4323034Sdougm 	char *valuestr;
4333034Sdougm 	int ret = SA_OK;
4343348Sdougm 	int have_path = 0;
4353034Sdougm 
4363034Sdougm 	/*
4373034Sdougm 	 * While preliminary check (starts with 'S') passed before
4383034Sdougm 	 * getting here. Need to make sure it is in ID syntax
4393034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
4403034Sdougm 	 * pgroups.
4413034Sdougm 	 */
4423034Sdougm 	vallen = strlen(id);
4433034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
444*4653Sdougm 		uuid_t uuid;
445*4653Sdougm 		if (strncmp(id, SA_SHARE_PG_PREFIX,
446*4653Sdougm 		    SA_SHARE_PG_PREFIXLEN) != 0 ||
447*4653Sdougm 		    uuid_parse(id + 2, uuid) < 0)
448*4653Sdougm 			return;
449*4653Sdougm 	} else {
4503034Sdougm 		return;
4513034Sdougm 	}
4523034Sdougm 
4533034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
4543034Sdougm 
4553034Sdougm 	iter = scf_iter_create(handle->handle);
4563034Sdougm 	value = scf_value_create(handle->handle);
4573034Sdougm 	prop = scf_property_create(handle->handle);
4583034Sdougm 	name = malloc(scf_max_name_len);
4593034Sdougm 	valuestr = malloc(vallen);
4603034Sdougm 
4613034Sdougm 	/*
462*4653Sdougm 	 * Construct the share XML node. It is similar to sa_add_share
4633034Sdougm 	 * but never changes the repository. Also, there won't be any
4643034Sdougm 	 * ZFS or transient shares.  Root will be the group it is
4653034Sdougm 	 * associated with.
4663034Sdougm 	 */
4673034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
4683034Sdougm 	if (node != NULL) {
4693034Sdougm 		/*
470*4653Sdougm 		 * Make sure the UUID part of the property group is
4713034Sdougm 		 * stored in the share "id" property. We use this
4723034Sdougm 		 * later.
4733034Sdougm 		 */
474*4653Sdougm 		xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
475*4653Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
4763034Sdougm 	}
4773034Sdougm 
478*4653Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
479*4653Sdougm 		goto out;
480*4653Sdougm 
481*4653Sdougm 	/* Iterate over the share pg properties */
482*4653Sdougm 	if (scf_iter_pg_properties(iter, pg) != 0)
483*4653Sdougm 		goto out;
484*4653Sdougm 
485*4653Sdougm 	while (scf_iter_next_property(iter, prop) > 0) {
486*4653Sdougm 		ret = SA_SYSTEM_ERR; /* assume the worst */
487*4653Sdougm 		if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
4883034Sdougm 			if (scf_property_get_value(prop, value) == 0) {
489*4653Sdougm 				if (scf_value_get_astring(value, valuestr,
490*4653Sdougm 				    vallen) >= 0) {
491*4653Sdougm 					ret = SA_OK;
492*4653Sdougm 				}
4933034Sdougm 			}
494*4653Sdougm 		}
495*4653Sdougm 		if (ret == SA_OK) {
4963348Sdougm 			/*
497*4653Sdougm 			 * Check that we have the "path" property in
4983348Sdougm 			 * name. The string in name will always be nul
4993348Sdougm 			 * terminated if scf_property_get_name()
5003348Sdougm 			 * succeeded.
5013348Sdougm 			 */
5023348Sdougm 			if (strcmp(name, "path") == 0)
503*4653Sdougm 				have_path = 1;
5043034Sdougm 			if (is_share_attr(name)) {
5053034Sdougm 				/*
506*4653Sdougm 				 * If a share attr, then simple -
5073034Sdougm 				 * usually path and resource name
5083034Sdougm 				 */
509*4653Sdougm 				xmlSetProp(node, (xmlChar *)name,
510*4653Sdougm 				    (xmlChar *)valuestr);
5113034Sdougm 			} else {
512*4653Sdougm 				if (strcmp(name, "description") == 0) {
513*4653Sdougm 					/* We have a description node */
514*4653Sdougm 					xmlNodePtr desc;
515*4653Sdougm 					desc = xmlNewChild(node, NULL,
516*4653Sdougm 					    (xmlChar *)"description", NULL);
517*4653Sdougm 					if (desc != NULL)
518*4653Sdougm 						xmlNodeSetContent(desc,
519*4653Sdougm 						    (xmlChar *)valuestr);
520*4653Sdougm 				}
5213034Sdougm 			}
5223034Sdougm 		}
5233034Sdougm 	}
524*4653Sdougm out:
5253348Sdougm 	/*
526*4653Sdougm 	 * A share without a path is broken so we want to not include
5273348Sdougm 	 * these.  They shouldn't happen but if you kill a sharemgr in
5283348Sdougm 	 * the process of creating a share, it could happen.  They
5293348Sdougm 	 * should be harmless.  It is also possible that another
5303348Sdougm 	 * sharemgr is running and in the process of creating a share.
5313348Sdougm 	 */
5323348Sdougm 	if (have_path == 0 && node != NULL) {
533*4653Sdougm 		xmlUnlinkNode(node);
534*4653Sdougm 		xmlFreeNode(node);
5353348Sdougm 	}
5363034Sdougm 	if (name != NULL)
537*4653Sdougm 		free(name);
5383034Sdougm 	if (valuestr != NULL)
539*4653Sdougm 		free(valuestr);
5403034Sdougm 	if (value != NULL)
541*4653Sdougm 		scf_value_destroy(value);
5423034Sdougm 	if (iter != NULL)
543*4653Sdougm 		scf_iter_destroy(iter);
5443034Sdougm 	if (prop != NULL)
545*4653Sdougm 		scf_property_destroy(prop);
5463034Sdougm }
5473034Sdougm 
5483034Sdougm /*
5493034Sdougm  * find_share_by_id(shareid)
5503034Sdougm  *
5513034Sdougm  * Search all shares in all groups until we find the share represented
5523034Sdougm  * by "id".
5533034Sdougm  */
5543034Sdougm 
5553034Sdougm static sa_share_t
5563910Sdougm find_share_by_id(sa_handle_t handle, char *shareid)
5573034Sdougm {
5583034Sdougm 	sa_group_t group;
5593034Sdougm 	sa_share_t share = NULL;
5603034Sdougm 	char *id = NULL;
5613034Sdougm 	int done = 0;
5623034Sdougm 
563*4653Sdougm 	for (group = sa_get_group(handle, NULL);
564*4653Sdougm 	    group != NULL && !done;
565*4653Sdougm 	    group = sa_get_next_group(group)) {
566*4653Sdougm 		for (share = sa_get_share(group, NULL);
567*4653Sdougm 		    share != NULL;
568*4653Sdougm 		    share = sa_get_next_share(share)) {
5693034Sdougm 			id = sa_get_share_attr(share, "id");
5703034Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
5713034Sdougm 				sa_free_attr_string(id);
5723034Sdougm 				id = NULL;
5733034Sdougm 				done++;
5743034Sdougm 				break;
5753034Sdougm 			}
5763034Sdougm 			if (id != NULL) {
577*4653Sdougm 				sa_free_attr_string(id);
578*4653Sdougm 				id = NULL;
5793034Sdougm 			}
5803034Sdougm 		}
5813034Sdougm 	}
5823034Sdougm 	return (share);
5833034Sdougm }
5843034Sdougm 
5853034Sdougm /*
5863034Sdougm  * sa_share_props_from_pgroup(root, handle, pg, id)
5873034Sdougm  *
588*4653Sdougm  * Extract share properties from the SMF property group. More sanity
5893034Sdougm  * checks are done and the share object is created. We ignore some
5903034Sdougm  * errors that could exist in the repository and only worry about
5913034Sdougm  * property groups that validate in naming.
5923034Sdougm  */
5933034Sdougm 
5943034Sdougm static int
5953034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
5963910Sdougm 			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
5973034Sdougm {
5983034Sdougm 	xmlNodePtr node;
599*4653Sdougm 	char *name = NULL;
600*4653Sdougm 	scf_iter_t *iter = NULL;
601*4653Sdougm 	scf_property_t *prop = NULL;
602*4653Sdougm 	scf_value_t *value = NULL;
6033034Sdougm 	ssize_t vallen;
604*4653Sdougm 	char *valuestr = NULL;
6053034Sdougm 	int ret = SA_OK;
6063034Sdougm 	char *sectype = NULL;
6073034Sdougm 	char *proto;
6083034Sdougm 	sa_share_t share;
609*4653Sdougm 	uuid_t uuid;
6103034Sdougm 
6113034Sdougm 	/*
6123034Sdougm 	 * While preliminary check (starts with 'S') passed before
6133034Sdougm 	 * getting here. Need to make sure it is in ID syntax
6143034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
6153034Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
6163034Sdougm 	 * characters, it is likely one of the protocol/security
6173034Sdougm 	 * versions.
6183034Sdougm 	 */
6193034Sdougm 	vallen = strlen(id);
620*4653Sdougm 	if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
621*4653Sdougm 		/*
622*4653Sdougm 		 * It is ok to not have what we thought since someone might
623*4653Sdougm 		 * have added a name via SMF.
624*4653Sdougm 		 */
625*4653Sdougm 		return (ret);
626*4653Sdougm 	}
627*4653Sdougm 	if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
6283034Sdougm 		proto = strchr(id, '_');
6293034Sdougm 		if (proto == NULL)
630*4653Sdougm 			return (ret);
6313034Sdougm 		*proto++ = '\0';
6323034Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
633*4653Sdougm 			return (ret);
6343034Sdougm 		/*
6353034Sdougm 		 * probably a legal optionset so check a few more
6363034Sdougm 		 * syntax points below.
6373034Sdougm 		 */
6383034Sdougm 		if (*proto == '\0') {
639*4653Sdougm 			/* not a valid proto (null) */
640*4653Sdougm 			return (ret);
6413034Sdougm 		}
6423034Sdougm 		sectype = strchr(proto, '_');
6433034Sdougm 		if (sectype != NULL)
644*4653Sdougm 			*sectype++ = '\0';
6453034Sdougm 		if (!valid_protocol(proto))
646*4653Sdougm 			return (ret);
6473034Sdougm 	}
6483034Sdougm 
6493034Sdougm 	/*
650*4653Sdougm 	 * To get here, we have a valid protocol and possibly a
6513034Sdougm 	 * security. We now have to find the share that it is really
6523034Sdougm 	 * associated with. The "id" portion of the pgroup name will
6533034Sdougm 	 * match.
6543034Sdougm 	 */
6553034Sdougm 
6563910Sdougm 	share = find_share_by_id(sahandle, id);
6573034Sdougm 	if (share == NULL)
658*4653Sdougm 		return (SA_BAD_PATH);
6593034Sdougm 
6603034Sdougm 	root = (xmlNodePtr)share;
6613034Sdougm 
6623034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
6633034Sdougm 
664*4653Sdougm 	if (sectype == NULL)
665*4653Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
666*4653Sdougm 	else {
667*4653Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
668*4653Sdougm 		if (node != NULL)
669*4653Sdougm 			xmlSetProp(node, (xmlChar *)"sectype",
670*4653Sdougm 			    (xmlChar *)sectype);
671*4653Sdougm 	}
672*4653Sdougm 	if (node == NULL) {
673*4653Sdougm 		ret = SA_NO_MEMORY;
674*4653Sdougm 		goto out;
675*4653Sdougm 	}
676*4653Sdougm 
677*4653Sdougm 	xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
678*4653Sdougm 	/* now find the properties */
6793034Sdougm 	iter = scf_iter_create(handle->handle);
6803034Sdougm 	value = scf_value_create(handle->handle);
6813034Sdougm 	prop = scf_property_create(handle->handle);
6823034Sdougm 	name = malloc(scf_max_name_len);
6833034Sdougm 	valuestr = malloc(vallen);
6843034Sdougm 
685*4653Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
686*4653Sdougm 		goto out;
687*4653Sdougm 
688*4653Sdougm 	/* Iterate over the share pg properties */
689*4653Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
690*4653Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
6913034Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
6923034Sdougm 			if (scf_property_get_name(prop, name,
693*4653Sdougm 			    scf_max_name_len) > 0) {
694*4653Sdougm 				if (scf_property_get_value(prop, value) == 0) {
695*4653Sdougm 					if (scf_value_get_astring(value,
696*4653Sdougm 					    valuestr, vallen) >= 0) {
697*4653Sdougm 						ret = SA_OK;
698*4653Sdougm 					}
6993034Sdougm 				}
7003034Sdougm 			} else {
701*4653Sdougm 				ret = SA_SYSTEM_ERR;
7023034Sdougm 			}
7033034Sdougm 			if (ret == SA_OK) {
704*4653Sdougm 				sa_property_t prop;
705*4653Sdougm 				prop = sa_create_property(name, valuestr);
706*4653Sdougm 				if (prop != NULL)
707*4653Sdougm 					prop = (sa_property_t)xmlAddChild(node,
708*4653Sdougm 					    (xmlNodePtr)prop);
709*4653Sdougm 				else
710*4653Sdougm 					ret = SA_NO_MEMORY;
7113034Sdougm 			}
7123034Sdougm 		}
7133034Sdougm 	} else {
714*4653Sdougm 		ret = SA_SYSTEM_ERR;
7153034Sdougm 	}
716*4653Sdougm out:
7173034Sdougm 	if (iter != NULL)
718*4653Sdougm 		scf_iter_destroy(iter);
7193034Sdougm 	if (value != NULL)
720*4653Sdougm 		scf_value_destroy(value);
7213034Sdougm 	if (prop != NULL)
722*4653Sdougm 		scf_property_destroy(prop);
7233034Sdougm 	if (name != NULL)
724*4653Sdougm 		free(name);
7253034Sdougm 	if (valuestr != NULL)
726*4653Sdougm 		free(valuestr);
7273034Sdougm 	return (ret);
7283034Sdougm }
7293034Sdougm 
7303034Sdougm /*
7313034Sdougm  * sa_extract_group(root, handle, instance)
7323034Sdougm  *
733*4653Sdougm  * Get the config info for this instance of a group and create the XML
7343034Sdougm  * subtree from it.
7353034Sdougm  */
7363034Sdougm 
7373034Sdougm static int
7383034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
7393910Sdougm 			scf_instance_t *instance, sa_handle_t sahandle)
7403034Sdougm {
7413034Sdougm 	char *buff;
7423034Sdougm 	xmlNodePtr node;
7433034Sdougm 	scf_iter_t *iter;
7443034Sdougm 	char *proto;
7453034Sdougm 	char *sectype;
7463034Sdougm 	int have_shares = 0;
7473034Sdougm 	int has_proto = 0;
7483034Sdougm 	int is_default = 0;
7493034Sdougm 	int ret = SA_OK;
7503034Sdougm 	int err;
7513034Sdougm 
7523034Sdougm 	buff = malloc(scf_max_name_len);
753*4653Sdougm 	if (buff == NULL)
754*4653Sdougm 		return (SA_NO_MEMORY);
755*4653Sdougm 
7563034Sdougm 	iter = scf_iter_create(handle->handle);
757*4653Sdougm 	if (iter == NULL) {
758*4653Sdougm 		ret = SA_NO_MEMORY;
759*4653Sdougm 		goto out;
760*4653Sdougm 	}
761*4653Sdougm 
762*4653Sdougm 	if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
7633034Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
764*4653Sdougm 		if (node == NULL) {
765*4653Sdougm 			ret = SA_NO_MEMORY;
766*4653Sdougm 			goto out;
767*4653Sdougm 		}
768*4653Sdougm 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
769*4653Sdougm 		if (strcmp(buff, "default") == 0)
7703034Sdougm 			is_default++;
771*4653Sdougm 
772*4653Sdougm 		sa_extract_attrs(node, handle, instance);
773*4653Sdougm 		/*
774*4653Sdougm 		 * Iterate through all the property groups
775*4653Sdougm 		 * looking for those with security or
776*4653Sdougm 		 * optionset prefixes. The names of the
777*4653Sdougm 		 * matching pgroups are parsed to get the
778*4653Sdougm 		 * protocol, and for security, the sectype.
779*4653Sdougm 		 * Syntax is as follows:
780*4653Sdougm 		 *    optionset | optionset_<proto>
781*4653Sdougm 		 *    security_default | security_<proto>_<sectype>
782*4653Sdougm 		 * "operation" is handled by
783*4653Sdougm 		 * sa_extract_attrs().
784*4653Sdougm 		 */
785*4653Sdougm 		if (scf_iter_instance_pgs(iter, instance) != 0) {
786*4653Sdougm 			ret = SA_NO_MEMORY;
787*4653Sdougm 			goto out;
788*4653Sdougm 		}
789*4653Sdougm 		while (scf_iter_next_pg(iter, handle->pg) > 0) {
790*4653Sdougm 			/* Have a pgroup so sort it out */
791*4653Sdougm 			ret = scf_pg_get_name(handle->pg, buff,
792*4653Sdougm 			    scf_max_name_len);
793*4653Sdougm 			if (ret  > 0) {
794*4653Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
7953034Sdougm 					sa_share_from_pgroup(node, handle,
796*4653Sdougm 					    handle->pg, buff);
7973034Sdougm 					have_shares++;
798*4653Sdougm 				} else if (strncmp(buff, "optionset", 9) ==
799*4653Sdougm 				    0) {
8003034Sdougm 					char *nodetype = "optionset";
801*4653Sdougm 					/* Have an optionset */
8023034Sdougm 					sectype = NULL;
8033034Sdougm 					proto = strchr(buff, '_');
8043034Sdougm 					if (proto != NULL) {
805*4653Sdougm 						*proto++ = '\0';
806*4653Sdougm 						sectype = strchr(proto, '_');
807*4653Sdougm 						if (sectype != NULL) {
808*4653Sdougm 							*sectype++ = '\0';
809*4653Sdougm 							nodetype = "security";
810*4653Sdougm 						}
8113034Sdougm 					}
8123034Sdougm 					ret = sa_extract_pgroup(node, handle,
813*4653Sdougm 					    handle->pg, nodetype, proto,
814*4653Sdougm 					    sectype);
8153034Sdougm 					has_proto++;
816*4653Sdougm 				} else if (strncmp(buff, "security", 8) == 0) {
8173034Sdougm 					/*
818*4653Sdougm 					 * Have a security (note that
8193034Sdougm 					 * this should change in the
8203034Sdougm 					 * future)
8213034Sdougm 					 */
8223034Sdougm 					proto = strchr(buff, '_');
8233034Sdougm 					sectype = NULL;
8243034Sdougm 					if (proto != NULL) {
825*4653Sdougm 						*proto++ = '\0';
826*4653Sdougm 						sectype = strchr(proto, '_');
827*4653Sdougm 						if (sectype != NULL)
828*4653Sdougm 							*sectype++ = '\0';
829*4653Sdougm 						if (strcmp(proto, "default") ==
830*4653Sdougm 						    0)
831*4653Sdougm 							proto = NULL;
8323034Sdougm 					}
8333034Sdougm 					ret = sa_extract_pgroup(node, handle,
834*4653Sdougm 					    handle->pg, "security", proto,
835*4653Sdougm 					    sectype);
8363034Sdougm 					has_proto++;
8373034Sdougm 				}
838*4653Sdougm 				/* Ignore everything else */
8393034Sdougm 			}
840*4653Sdougm 		}
841*4653Sdougm 		/*
842*4653Sdougm 		 * Make sure we have a valid default group.
843*4653Sdougm 		 * On first boot, default won't have any
844*4653Sdougm 		 * protocols defined and won't be enabled (but
845*4653Sdougm 		 * should be).
846*4653Sdougm 		 */
847*4653Sdougm 		if (is_default) {
848*4653Sdougm 			char *state = sa_get_group_attr((sa_group_t)node,
849*4653Sdougm 			    "state");
850*4653Sdougm 			char **protos;
851*4653Sdougm 			int numprotos;
852*4653Sdougm 			int i;
8533034Sdougm 
854*4653Sdougm 			if (state == NULL) {
8553034Sdougm 				/* set attribute to enabled */
8563034Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
857*4653Sdougm 				    "state", "enabled");
858*4653Sdougm 				/* We can assume no protocols */
8593034Sdougm 				numprotos = sa_get_protocols(&protos);
8603034Sdougm 				for (i = 0; i < numprotos; i++)
861*4653Sdougm 					(void) sa_create_optionset(
862*4653Sdougm 					    (sa_group_t)node, protos[i]);
8633034Sdougm 				if (numprotos > 0)
864*4653Sdougm 					free(protos);
865*4653Sdougm 			} else {
8663034Sdougm 				sa_free_attr_string(state);
8673034Sdougm 			}
868*4653Sdougm 		}
869*4653Sdougm 		/* Do a second pass if shares were found */
870*4653Sdougm 		if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
871*4653Sdougm 			while (scf_iter_next_pg(iter, handle->pg) > 0) {
8723034Sdougm 				/*
873*4653Sdougm 				 * Have a pgroup so see if it is a
8743034Sdougm 				 * share optionset
8753034Sdougm 				 */
8763034Sdougm 				err = scf_pg_get_name(handle->pg, buff,
877*4653Sdougm 				    scf_max_name_len);
878*4653Sdougm 				if (err  <= 0)
879*4653Sdougm 					continue;
880*4653Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
8813034Sdougm 					ret = sa_share_props_from_pgroup(node,
882*4653Sdougm 					    handle, handle->pg, buff,
883*4653Sdougm 					    sahandle);
8843034Sdougm 				}
8853034Sdougm 			}
8863034Sdougm 		}
8873034Sdougm 	}
888*4653Sdougm out:
8893034Sdougm 	if (iter != NULL)
890*4653Sdougm 		scf_iter_destroy(iter);
8913034Sdougm 	if (buff != NULL)
892*4653Sdougm 		free(buff);
8933034Sdougm 	return (ret);
8943034Sdougm }
8953034Sdougm 
8963034Sdougm /*
8973034Sdougm  * sa_extract_defaults(root, handle, instance)
8983034Sdougm  *
899*4653Sdougm  * Local function to find the default properties that live in the
9003034Sdougm  * default instance's "operation" proprerty group.
9013034Sdougm  */
9023034Sdougm 
9033034Sdougm static void
9043034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
9053034Sdougm 		    scf_instance_t *instance)
9063034Sdougm {
9073034Sdougm 	xmlNodePtr node;
9083034Sdougm 	scf_property_t *prop;
9093034Sdougm 	scf_value_t *value;
9103034Sdougm 	char *valuestr;
9113034Sdougm 	ssize_t vallen;
9123034Sdougm 
9133034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
9143034Sdougm 	prop = scf_property_create(handle->handle);
9153034Sdougm 	value = scf_value_create(handle->handle);
9163034Sdougm 	valuestr = malloc(vallen);
917*4653Sdougm 
918*4653Sdougm 	if (prop == NULL || value == NULL || vallen == 0 ||
919*4653Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0)
920*4653Sdougm 		goto out;
921*4653Sdougm 
922*4653Sdougm 	if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
923*4653Sdougm 		goto out;
924*4653Sdougm 
925*4653Sdougm 	/* Found the property so get the value */
926*4653Sdougm 	if (scf_property_get_value(prop, value) == 0) {
927*4653Sdougm 		if (scf_value_get_astring(value, valuestr, vallen) > 0) {
9283034Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
929*4653Sdougm 			    NULL);
9303034Sdougm 			if (node != NULL) {
931*4653Sdougm 				xmlSetProp(node, (xmlChar *)"timestamp",
932*4653Sdougm 				    (xmlChar *)valuestr);
933*4653Sdougm 				xmlSetProp(node, (xmlChar *)"path",
934*4653Sdougm 				    (xmlChar *)SA_LEGACY_DFSTAB);
9353034Sdougm 			}
9363034Sdougm 		}
9373034Sdougm 	}
938*4653Sdougm out:
9393034Sdougm 	if (valuestr != NULL)
940*4653Sdougm 		free(valuestr);
9413034Sdougm 	if (value != NULL)
942*4653Sdougm 		scf_value_destroy(value);
9433034Sdougm 	if (prop != NULL)
944*4653Sdougm 		scf_property_destroy(prop);
9453034Sdougm }
9463034Sdougm 
9473034Sdougm 
9483034Sdougm /*
9493910Sdougm  * sa_get_config(handle, root, doc, sahandlec)
9503034Sdougm  *
951*4653Sdougm  * Walk the SMF repository for /network/shares/group and find all the
9523034Sdougm  * instances. These become group names.  Then add the XML structure
9533034Sdougm  * below the groups based on property groups and properties.
9543034Sdougm  */
9553034Sdougm int
9563973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
9573034Sdougm {
9583034Sdougm 	int ret = SA_OK;
9593034Sdougm 	scf_instance_t *instance;
9603034Sdougm 	scf_iter_t *iter;
9613034Sdougm 	char buff[BUFSIZ * 2];
9623034Sdougm 
9633034Sdougm 	instance = scf_instance_create(handle->handle);
9643034Sdougm 	iter = scf_iter_create(handle->handle);
9653973Sdougm 	if (instance != NULL && iter != NULL) {
966*4653Sdougm 		if ((ret = scf_iter_service_instances(iter,
967*4653Sdougm 		    handle->service)) == 0) {
968*4653Sdougm 			while ((ret = scf_iter_next_instance(iter,
969*4653Sdougm 			    instance)) > 0) {
970*4653Sdougm 				if (scf_instance_get_name(instance, buff,
971*4653Sdougm 				    sizeof (buff)) > 0) {
972*4653Sdougm 					if (strcmp(buff, "default") == 0)
973*4653Sdougm 						sa_extract_defaults(root,
974*4653Sdougm 						    handle, instance);
975*4653Sdougm 					ret = sa_extract_group(root, handle,
976*4653Sdougm 					    instance, sahandle);
977*4653Sdougm 				}
978*4653Sdougm 			}
9793034Sdougm 		}
9803034Sdougm 	}
9813973Sdougm 
982*4653Sdougm 	/* Always cleanup these */
9833034Sdougm 	if (instance != NULL)
984*4653Sdougm 		scf_instance_destroy(instance);
9853034Sdougm 	if (iter != NULL)
986*4653Sdougm 		scf_iter_destroy(iter);
9873034Sdougm 	return (ret);
9883034Sdougm }
9893034Sdougm 
9903034Sdougm /*
9913034Sdougm  * sa_get_instance(handle, instance)
9923034Sdougm  *
993*4653Sdougm  * Get the instance of the group service. This is actually the
9943034Sdougm  * specific group name. The instance is needed for all property and
9953034Sdougm  * control operations.
9963034Sdougm  */
9973034Sdougm 
9983034Sdougm int
9993034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
10003034Sdougm {
10013034Sdougm 	if (scf_service_get_instance(handle->service, instname,
1002*4653Sdougm 	    handle->instance) != 0) {
1003*4653Sdougm 		return (SA_NO_SUCH_GROUP);
10043034Sdougm 	}
10053034Sdougm 	return (SA_OK);
10063034Sdougm }
10073034Sdougm 
10083034Sdougm /*
10093034Sdougm  * sa_create_instance(handle, instname)
10103034Sdougm  *
10113034Sdougm  * Create a new SMF service instance. There can only be one with a
10123034Sdougm  * given name.
10133034Sdougm  */
10143034Sdougm 
10153034Sdougm int
10163034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
10173034Sdougm {
10183034Sdougm 	int ret = SA_OK;
10193034Sdougm 	char instance[SA_GROUP_INST_LEN];
10203034Sdougm 	if (scf_service_add_instance(handle->service, instname,
1021*4653Sdougm 	    handle->instance) != 0) {
10223034Sdougm 	/* better error returns need to be added based on real error */
1023*4653Sdougm 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
1024*4653Sdougm 			ret = SA_NO_PERMISSION;
1025*4653Sdougm 		else
1026*4653Sdougm 			ret = SA_DUPLICATE_NAME;
10273034Sdougm 	} else {
1028*4653Sdougm 		/* have the service created, so enable it */
1029*4653Sdougm 		(void) snprintf(instance, sizeof (instance), "%s:%s",
1030*4653Sdougm 		    SA_SVC_FMRI_BASE, instname);
1031*4653Sdougm 		(void) smf_enable_instance(instance, 0);
10323034Sdougm 	}
10333034Sdougm 	return (ret);
10343034Sdougm }
10353034Sdougm 
10363034Sdougm /*
10373034Sdougm  * sa_delete_instance(handle, instname)
10383034Sdougm  *
10393034Sdougm  * When a group goes away, we also remove the service instance.
10403034Sdougm  */
10413034Sdougm 
10423034Sdougm int
10433034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
10443034Sdougm {
10453034Sdougm 	int ret;
10463034Sdougm 
10473034Sdougm 	if (strcmp(instname, "default") == 0) {
1048*4653Sdougm 		ret = SA_NO_PERMISSION;
10493034Sdougm 	} else {
1050*4653Sdougm 		if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
1051*4653Sdougm 			if (scf_instance_delete(handle->instance) != 0)
1052*4653Sdougm 				/* need better analysis */
1053*4653Sdougm 				ret = SA_NO_PERMISSION;
1054*4653Sdougm 		}
10553034Sdougm 	}
10563034Sdougm 	return (ret);
10573034Sdougm }
10583034Sdougm 
10593034Sdougm /*
10603034Sdougm  * sa_create_pgroup(handle, pgroup)
10613034Sdougm  *
10623034Sdougm  * create a new property group
10633034Sdougm  */
10643034Sdougm 
10653034Sdougm int
10663034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
10673034Sdougm {
10683034Sdougm 	int ret = SA_OK;
10693034Sdougm 	/*
1070*4653Sdougm 	 * Only create a handle if it doesn't exist. It is ok to exist
10713034Sdougm 	 * since the pg handle will be set as a side effect.
10723034Sdougm 	 */
1073*4653Sdougm 	if (handle->pg == NULL)
1074*4653Sdougm 		handle->pg = scf_pg_create(handle->handle);
1075*4653Sdougm 
10763034Sdougm 	/*
1077*4653Sdougm 	 * If the pgroup exists, we are done. If it doesn't, then we
10783034Sdougm 	 * need to actually add one to the service instance.
10793034Sdougm 	 */
10803034Sdougm 	if (scf_instance_get_pg(handle->instance,
1081*4653Sdougm 	    pgroup, handle->pg) != 0) {
1082*4653Sdougm 		/* Doesn't exist so create one */
1083*4653Sdougm 		if (scf_instance_add_pg(handle->instance, pgroup,
1084*4653Sdougm 		    SCF_GROUP_APPLICATION, 0, handle->pg) != 0) {
1085*4653Sdougm 			switch (scf_error()) {
1086*4653Sdougm 			case SCF_ERROR_PERMISSION_DENIED:
1087*4653Sdougm 				ret = SA_NO_PERMISSION;
1088*4653Sdougm 				break;
1089*4653Sdougm 			default:
1090*4653Sdougm 				ret = SA_SYSTEM_ERR;
1091*4653Sdougm 				break;
1092*4653Sdougm 			}
10933034Sdougm 		}
10943034Sdougm 	}
10953034Sdougm 	return (ret);
10963034Sdougm }
10973034Sdougm 
10983034Sdougm /*
10993034Sdougm  * sa_delete_pgroup(handle, pgroup)
11003034Sdougm  *
1101*4653Sdougm  * Remove the property group from the current instance of the service,
11023034Sdougm  * but only if it actually exists.
11033034Sdougm  */
11043034Sdougm 
11053034Sdougm int
11063034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
11073034Sdougm {
11083034Sdougm 	int ret = SA_OK;
11093034Sdougm 	/*
1110*4653Sdougm 	 * Only delete if it does exist.
11113034Sdougm 	 */
1112*4653Sdougm 	if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
1113*4653Sdougm 		/* does exist so delete it */
1114*4653Sdougm 		if (scf_pg_delete(handle->pg) != 0)
1115*4653Sdougm 			ret = SA_SYSTEM_ERR;
1116*4653Sdougm 	} else {
11173034Sdougm 		ret = SA_SYSTEM_ERR;
11183034Sdougm 	}
11193034Sdougm 	if (ret == SA_SYSTEM_ERR &&
11203034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
11213034Sdougm 		ret = SA_NO_PERMISSION;
11223034Sdougm 	}
11233034Sdougm 	return (ret);
11243034Sdougm }
11253034Sdougm 
11263034Sdougm /*
11273034Sdougm  * sa_start_transaction(handle, pgroup)
11283034Sdougm  *
11293034Sdougm  * Start an SMF transaction so we can deal with properties. it would
11303034Sdougm  * be nice to not have to expose this, but we have to in order to
11313034Sdougm  * optimize.
11323034Sdougm  *
11333034Sdougm  * Basic model is to hold the transaction in the handle and allow
11343034Sdougm  * property adds/deletes/updates to be added then close the
11353034Sdougm  * transaction (or abort).  There may eventually be a need to handle
11363034Sdougm  * other types of transaction mechanisms but we don't do that now.
11373034Sdougm  *
11383034Sdougm  * An sa_start_transaction must be followed by either an
11393034Sdougm  * sa_end_transaction or sa_abort_transaction before another
11403034Sdougm  * sa_start_transaction can be done.
11413034Sdougm  */
11423034Sdougm 
11433034Sdougm int
11443034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
11453034Sdougm {
11463034Sdougm 	int ret = SA_OK;
11473034Sdougm 	/*
1148*4653Sdougm 	 * Lookup the property group and create it if it doesn't already
11493034Sdougm 	 * exist.
11503034Sdougm 	 */
11513034Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
1152*4653Sdougm 		ret = sa_create_pgroup(handle, propgroup);
1153*4653Sdougm 		if (ret == SA_OK) {
1154*4653Sdougm 			handle->trans = scf_transaction_create(handle->handle);
1155*4653Sdougm 			if (handle->trans != NULL) {
1156*4653Sdougm 				if (scf_transaction_start(handle->trans,
1157*4653Sdougm 				    handle->pg) != 0) {
1158*4653Sdougm 					ret = SA_SYSTEM_ERR;
1159*4653Sdougm 				}
1160*4653Sdougm 				if (ret != SA_OK) {
1161*4653Sdougm 					scf_transaction_destroy(handle->trans);
1162*4653Sdougm 					handle->trans = NULL;
1163*4653Sdougm 				}
1164*4653Sdougm 			} else {
1165*4653Sdougm 				ret = SA_SYSTEM_ERR;
1166*4653Sdougm 			}
11673034Sdougm 		}
11683034Sdougm 	}
11693034Sdougm 	if (ret == SA_SYSTEM_ERR &&
11703034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
11713034Sdougm 		ret = SA_NO_PERMISSION;
11723034Sdougm 	}
11733034Sdougm 	return (ret);
11743034Sdougm }
11753034Sdougm 
11763034Sdougm /*
11773034Sdougm  * sa_end_transaction(handle)
11783034Sdougm  *
11793034Sdougm  * Commit the changes that were added to the transaction in the
11803034Sdougm  * handle. Do all necessary cleanup.
11813034Sdougm  */
11823034Sdougm 
11833034Sdougm int
11843034Sdougm sa_end_transaction(scfutilhandle_t *handle)
11853034Sdougm {
11863034Sdougm 	int ret = SA_OK;
11873034Sdougm 
11883034Sdougm 	if (handle->trans == NULL) {
1189*4653Sdougm 		ret = SA_SYSTEM_ERR;
11903034Sdougm 	} else {
1191*4653Sdougm 		if (scf_transaction_commit(handle->trans) < 0)
1192*4653Sdougm 			ret = SA_SYSTEM_ERR;
1193*4653Sdougm 		scf_transaction_destroy_children(handle->trans);
1194*4653Sdougm 		scf_transaction_destroy(handle->trans);
1195*4653Sdougm 		handle->trans = NULL;
11963034Sdougm 	}
11973034Sdougm 	return (ret);
11983034Sdougm }
11993034Sdougm 
12003034Sdougm /*
12013034Sdougm  * sa_abort_transaction(handle)
12023034Sdougm  *
12033034Sdougm  * Abort the changes that were added to the transaction in the
12043034Sdougm  * handle. Do all necessary cleanup.
12053034Sdougm  */
12063034Sdougm 
12073034Sdougm void
12083034Sdougm sa_abort_transaction(scfutilhandle_t *handle)
12093034Sdougm {
12103034Sdougm 	if (handle->trans != NULL) {
1211*4653Sdougm 		scf_transaction_reset_all(handle->trans);
1212*4653Sdougm 		scf_transaction_destroy_children(handle->trans);
1213*4653Sdougm 		scf_transaction_destroy(handle->trans);
1214*4653Sdougm 		handle->trans = NULL;
12153034Sdougm 	}
12163034Sdougm }
12173034Sdougm 
12183034Sdougm /*
12193034Sdougm  * sa_set_property(handle, prop, value)
12203034Sdougm  *
1221*4653Sdougm  * Set a property transaction entry into the pending SMF transaction.
12223034Sdougm  */
12233034Sdougm 
12243034Sdougm int
12253034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
12263034Sdougm {
12273034Sdougm 	int ret = SA_OK;
12283034Sdougm 	scf_value_t *value;
12293034Sdougm 	scf_transaction_entry_t *entry;
12303034Sdougm 	/*
1231*4653Sdougm 	 * Properties must be set in transactions and don't take
12323034Sdougm 	 * effect until the transaction has been ended/committed.
12333034Sdougm 	 */
12343034Sdougm 	value = scf_value_create(handle->handle);
12353034Sdougm 	entry = scf_entry_create(handle->handle);
12363034Sdougm 	if (value != NULL && entry != NULL) {
1237*4653Sdougm 		if (scf_transaction_property_change(handle->trans, entry,
1238*4653Sdougm 		    propname, SCF_TYPE_ASTRING) == 0 ||
1239*4653Sdougm 		    scf_transaction_property_new(handle->trans, entry,
1240*4653Sdougm 		    propname, SCF_TYPE_ASTRING) == 0) {
1241*4653Sdougm 			if (scf_value_set_astring(value, valstr) == 0) {
1242*4653Sdougm 				if (scf_entry_add_value(entry, value) != 0) {
1243*4653Sdougm 					ret = SA_SYSTEM_ERR;
1244*4653Sdougm 					scf_value_destroy(value);
1245*4653Sdougm 				}
1246*4653Sdougm 				/* The value is in the transaction */
1247*4653Sdougm 				value = NULL;
1248*4653Sdougm 			} else {
1249*4653Sdougm 				/* Value couldn't be constructed */
1250*4653Sdougm 				ret = SA_SYSTEM_ERR;
1251*4653Sdougm 			}
1252*4653Sdougm 			/* The entry is in the transaction */
1253*4653Sdougm 			entry = NULL;
1254*4653Sdougm 		} else {
12553034Sdougm 			ret = SA_SYSTEM_ERR;
12563034Sdougm 		}
1257*4653Sdougm 	} else {
12583034Sdougm 		ret = SA_SYSTEM_ERR;
12593034Sdougm 	}
12603034Sdougm 	if (ret == SA_SYSTEM_ERR) {
1261*4653Sdougm 		switch (scf_error()) {
1262*4653Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
1263*4653Sdougm 			ret = SA_NO_PERMISSION;
1264*4653Sdougm 			break;
1265*4653Sdougm 		}
12663034Sdougm 	}
12673034Sdougm 	/*
1268*4653Sdougm 	 * Cleanup if there were any errors that didn't leave these
12693034Sdougm 	 * values where they would be cleaned up later.
12703034Sdougm 	 */
12713034Sdougm 	if (value != NULL)
1272*4653Sdougm 		scf_value_destroy(value);
12733034Sdougm 	if (entry != NULL)
1274*4653Sdougm 		scf_entry_destroy(entry);
12753034Sdougm 	return (ret);
12763034Sdougm }
12773034Sdougm 
12783034Sdougm /*
12793034Sdougm  * sa_commit_share(handle, group, share)
12803034Sdougm  *
1281*4653Sdougm  *	Commit this share to the repository.
12823034Sdougm  *	properties are added if they exist but can be added later.
12833034Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
12843034Sdougm  */
12853034Sdougm int
12863034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
12873034Sdougm {
12883034Sdougm 	int ret = SA_OK;
12893034Sdougm 	char *groupname;
12903034Sdougm 	char *name;
12913034Sdougm 	char *resource;
12923034Sdougm 	char *description;
12933034Sdougm 	char *sharename;
12943034Sdougm 	ssize_t proplen;
12953034Sdougm 	char *propstring;
12963034Sdougm 
12973034Sdougm 	/*
1298*4653Sdougm 	 * Don't commit in the zfs group. We do commit legacy
12993034Sdougm 	 * (default) and all other groups/shares. ZFS is handled
13003034Sdougm 	 * through the ZFS configuration rather than SMF.
13013034Sdougm 	 */
13023034Sdougm 
13033034Sdougm 	groupname = sa_get_group_attr(group, "name");
13043034Sdougm 	if (groupname != NULL) {
1305*4653Sdougm 		if (strcmp(groupname, "zfs") == 0) {
1306*4653Sdougm 			/*
1307*4653Sdougm 			 * Adding to the ZFS group will result in the sharenfs
1308*4653Sdougm 			 * property being set but we don't want to do anything
1309*4653Sdougm 			 * SMF related at this point.
1310*4653Sdougm 			 */
1311*4653Sdougm 			sa_free_attr_string(groupname);
1312*4653Sdougm 			return (ret);
1313*4653Sdougm 		}
13143034Sdougm 	}
13153034Sdougm 
13163034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
13173034Sdougm 	propstring = malloc(proplen);
13183034Sdougm 	if (propstring == NULL)
1319*4653Sdougm 		ret = SA_NO_MEMORY;
13203034Sdougm 
13213034Sdougm 	if (groupname != NULL && ret == SA_OK) {
1322*4653Sdougm 		ret = sa_get_instance(handle, groupname);
1323*4653Sdougm 		sa_free_attr_string(groupname);
1324*4653Sdougm 		groupname = NULL;
1325*4653Sdougm 		sharename = sa_get_share_attr(share, "id");
1326*4653Sdougm 		if (sharename == NULL) {
1327*4653Sdougm 			/* slipped by */
1328*4653Sdougm 			char shname[SA_SHARE_UUID_BUFLEN];
1329*4653Sdougm 			generate_unique_sharename(shname);
1330*4653Sdougm 			xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
13313034Sdougm 			    (xmlChar *)shname);
1332*4653Sdougm 			sharename = strdup(shname);
13333034Sdougm 		}
1334*4653Sdougm 		if (sharename != NULL) {
1335*4653Sdougm 			sigset_t old, new;
1336*4653Sdougm 			/*
1337*4653Sdougm 			 * Have a share name allocated so create a pgroup for
1338*4653Sdougm 			 * it. It may already exist, but that is OK.  In order
1339*4653Sdougm 			 * to avoid creating a share pgroup that doesn't have
1340*4653Sdougm 			 * a path property, block signals around the critical
1341*4653Sdougm 			 * region of creating the share pgroup and props.
1342*4653Sdougm 			 */
1343*4653Sdougm 			(void) sigprocmask(SIG_BLOCK, NULL, &new);
1344*4653Sdougm 			(void) sigaddset(&new, SIGHUP);
1345*4653Sdougm 			(void) sigaddset(&new, SIGINT);
1346*4653Sdougm 			(void) sigaddset(&new, SIGQUIT);
1347*4653Sdougm 			(void) sigaddset(&new, SIGTSTP);
1348*4653Sdougm 			(void) sigprocmask(SIG_SETMASK, &new, &old);
1349*4653Sdougm 
1350*4653Sdougm 			ret = sa_create_pgroup(handle, sharename);
1351*4653Sdougm 			if (ret == SA_OK) {
1352*4653Sdougm 				/*
1353*4653Sdougm 				 * Now start the transaction for the
1354*4653Sdougm 				 * properties that define this share. They may
1355*4653Sdougm 				 * exist so attempt to update before create.
1356*4653Sdougm 				 */
1357*4653Sdougm 				ret = sa_start_transaction(handle, sharename);
1358*4653Sdougm 			}
1359*4653Sdougm 			if (ret == SA_OK) {
1360*4653Sdougm 				name = sa_get_share_attr(share, "path");
1361*4653Sdougm 				if (name != NULL) {
1362*4653Sdougm 					/*
1363*4653Sdougm 					 * There needs to be a path
1364*4653Sdougm 					 * for a share to exist.
1365*4653Sdougm 					 */
1366*4653Sdougm 					ret = sa_set_property(handle, "path",
1367*4653Sdougm 					    name);
1368*4653Sdougm 					sa_free_attr_string(name);
1369*4653Sdougm 				} else {
1370*4653Sdougm 					ret = SA_NO_MEMORY;
1371*4653Sdougm 				}
1372*4653Sdougm 			}
1373*4653Sdougm 			if (ret == SA_OK) {
1374*4653Sdougm 				resource = sa_get_share_attr(share,
1375*4653Sdougm 				    "resource");
1376*4653Sdougm 				if (resource != NULL) {
1377*4653Sdougm 					ret = sa_set_property(handle,
1378*4653Sdougm 					    "resource", resource);
1379*4653Sdougm 					sa_free_attr_string(resource);
1380*4653Sdougm 				}
1381*4653Sdougm 			}
1382*4653Sdougm 			if (ret == SA_OK) {
1383*4653Sdougm 				description = sa_get_share_description(share);
1384*4653Sdougm 				if (description != NULL) {
1385*4653Sdougm 					ret = sa_set_property(handle,
1386*4653Sdougm 					    "description",
1387*4653Sdougm 					    description);
1388*4653Sdougm 					sa_free_share_description(description);
1389*4653Sdougm 				}
1390*4653Sdougm 			}
1391*4653Sdougm 			/* Make sure we cleanup the transaction */
1392*4653Sdougm 			if (ret == SA_OK) {
1393*4653Sdougm 				ret = sa_end_transaction(handle);
1394*4653Sdougm 			} else {
1395*4653Sdougm 				sa_abort_transaction(handle);
1396*4653Sdougm 			}
1397*4653Sdougm 
1398*4653Sdougm 			(void) sigprocmask(SIG_SETMASK, &old, NULL);
1399*4653Sdougm 
1400*4653Sdougm 			free(sharename);
14013034Sdougm 		}
14023034Sdougm 	}
14033034Sdougm 	if (ret == SA_SYSTEM_ERR) {
1404*4653Sdougm 		int err = scf_error();
1405*4653Sdougm 		if (err == SCF_ERROR_PERMISSION_DENIED)
1406*4653Sdougm 			ret = SA_NO_PERMISSION;
14073034Sdougm 	}
14083034Sdougm 	if (propstring != NULL)
1409*4653Sdougm 		free(propstring);
14103034Sdougm 	if (groupname != NULL)
1411*4653Sdougm 		sa_free_attr_string(groupname);
14123034Sdougm 
14133034Sdougm 	return (ret);
14143034Sdougm }
14153034Sdougm 
14163034Sdougm /*
14173034Sdougm  * sa_delete_share(handle, group, share)
14183034Sdougm  *
1419*4653Sdougm  * Remove the specified share from the group (and service instance).
14203034Sdougm  */
14213034Sdougm 
14223034Sdougm int
14233034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
14243034Sdougm {
14253034Sdougm 	int ret = SA_OK;
14263034Sdougm 	char *groupname = NULL;
14273034Sdougm 	char *shareid = NULL;
14283034Sdougm 	sa_optionset_t opt;
14293034Sdougm 	sa_security_t sec;
14303034Sdougm 	ssize_t proplen;
14313034Sdougm 	char *propstring;
14323034Sdougm 
14333034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
14343034Sdougm 	propstring = malloc(proplen);
14353034Sdougm 	if (propstring == NULL)
1436*4653Sdougm 		ret = SA_NO_MEMORY;
14373034Sdougm 
14383034Sdougm 	if (ret == SA_OK) {
1439*4653Sdougm 		groupname = sa_get_group_attr(group, "name");
1440*4653Sdougm 		shareid = sa_get_share_attr(share, "id");
1441*4653Sdougm 		if (groupname == NULL || shareid == NULL) {
1442*4653Sdougm 			ret = SA_CONFIG_ERR;
1443*4653Sdougm 			goto out;
1444*4653Sdougm 		}
14453034Sdougm 		ret = sa_get_instance(handle, groupname);
14463034Sdougm 		if (ret == SA_OK) {
1447*4653Sdougm 			/* If a share has properties, remove them */
1448*4653Sdougm 			ret = sa_delete_pgroup(handle, shareid);
1449*4653Sdougm 			for (opt = sa_get_optionset(share, NULL);
1450*4653Sdougm 			    opt != NULL;
1451*4653Sdougm 			    opt = sa_get_next_optionset(opt)) {
1452*4653Sdougm 				char *proto;
1453*4653Sdougm 				proto = sa_get_optionset_attr(opt, "type");
1454*4653Sdougm 				if (proto != NULL) {
1455*4653Sdougm 					(void) snprintf(propstring,
1456*4653Sdougm 					    proplen, "%s_%s", shareid,
1457*4653Sdougm 					    proto);
1458*4653Sdougm 					ret = sa_delete_pgroup(handle,
1459*4653Sdougm 					    propstring);
1460*4653Sdougm 					sa_free_attr_string(proto);
1461*4653Sdougm 				} else {
1462*4653Sdougm 					ret = SA_NO_MEMORY;
1463*4653Sdougm 				}
14643034Sdougm 			}
14653034Sdougm 			/*
1466*4653Sdougm 			 * If a share has security/negotiable
14673034Sdougm 			 * properties, remove them.
14683034Sdougm 			 */
1469*4653Sdougm 			for (sec = sa_get_security(share, NULL, NULL);
1470*4653Sdougm 			    sec != NULL;
1471*4653Sdougm 			    sec = sa_get_next_security(sec)) {
1472*4653Sdougm 				char *proto;
1473*4653Sdougm 				char *sectype;
1474*4653Sdougm 				proto = sa_get_security_attr(sec, "type");
1475*4653Sdougm 				sectype = sa_get_security_attr(sec, "sectype");
1476*4653Sdougm 				if (proto != NULL && sectype != NULL) {
1477*4653Sdougm 					(void) snprintf(propstring, proplen,
1478*4653Sdougm 					    "%s_%s_%s", shareid,  proto,
1479*4653Sdougm 					    sectype);
1480*4653Sdougm 					ret = sa_delete_pgroup(handle,
1481*4653Sdougm 					    propstring);
1482*4653Sdougm 				} else {
1483*4653Sdougm 					ret = SA_NO_MEMORY;
1484*4653Sdougm 				}
1485*4653Sdougm 				if (proto != NULL)
1486*4653Sdougm 					sa_free_attr_string(proto);
1487*4653Sdougm 				if (sectype != NULL)
1488*4653Sdougm 					sa_free_attr_string(sectype);
14893034Sdougm 			}
14903034Sdougm 		}
14913034Sdougm 	}
1492*4653Sdougm out:
14933034Sdougm 	if (groupname != NULL)
1494*4653Sdougm 		sa_free_attr_string(groupname);
14953034Sdougm 	if (shareid != NULL)
1496*4653Sdougm 		sa_free_attr_string(shareid);
14973034Sdougm 	if (propstring != NULL)
1498*4653Sdougm 		free(propstring);
14993034Sdougm 
15003034Sdougm 	return (ret);
15013034Sdougm }
1502