xref: /titanic_50/usr/src/lib/libshare/common/scfutil.c (revision 25a68471b9ababbc21cfdbbb2866014f34f419ec)
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>
386185db85Sdougm #include <errno.h>
396185db85Sdougm #include <uuid/uuid.h>
406185db85Sdougm #include <sys/param.h>
41f345c0beSdougm #include <signal.h>
426185db85Sdougm 
436185db85Sdougm ssize_t scf_max_name_len;
446185db85Sdougm extern struct sa_proto_plugin *sap_proto_list;
45549ec3ffSdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
466185db85Sdougm 
476185db85Sdougm /*
486185db85Sdougm  * The SMF facility uses some properties that must exist. We want to
496185db85Sdougm  * skip over these when processing protocol options.
506185db85Sdougm  */
516185db85Sdougm static char *skip_props[] = {
526185db85Sdougm 	"modify_authorization",
536185db85Sdougm 	"action_authorization",
546185db85Sdougm 	"value_authorization",
556185db85Sdougm 	NULL
566185db85Sdougm };
576185db85Sdougm 
586185db85Sdougm /*
596185db85Sdougm  * sa_scf_fini(handle)
606185db85Sdougm  *
61*25a68471Sdougm  * Must be called when done. Called with the handle allocated in
626185db85Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
636185db85Sdougm  * still in use. Called by sa_fini().
646185db85Sdougm  */
656185db85Sdougm 
666185db85Sdougm void
676185db85Sdougm sa_scf_fini(scfutilhandle_t *handle)
686185db85Sdougm {
696185db85Sdougm 	if (handle != NULL) {
706185db85Sdougm 		int unbind = 0;
716185db85Sdougm 		if (handle->scope != NULL) {
726185db85Sdougm 			unbind = 1;
736185db85Sdougm 			scf_scope_destroy(handle->scope);
746185db85Sdougm 		}
75a3351425Sdougm 		if (handle->instance != NULL)
76a3351425Sdougm 			scf_instance_destroy(handle->instance);
776185db85Sdougm 		if (handle->service != NULL)
786185db85Sdougm 			scf_service_destroy(handle->service);
796185db85Sdougm 		if (handle->pg != NULL)
806185db85Sdougm 			scf_pg_destroy(handle->pg);
816185db85Sdougm 		if (handle->handle != NULL) {
826185db85Sdougm 			handle->scf_state = SCH_STATE_UNINIT;
836185db85Sdougm 			if (unbind)
846185db85Sdougm 				(void) scf_handle_unbind(handle->handle);
856185db85Sdougm 			scf_handle_destroy(handle->handle);
866185db85Sdougm 		}
876185db85Sdougm 		free(handle);
886185db85Sdougm 	}
896185db85Sdougm }
906185db85Sdougm 
916185db85Sdougm /*
926185db85Sdougm  * sa_scf_init()
936185db85Sdougm  *
94*25a68471Sdougm  * Must be called before using any of the SCF functions. Called by
956185db85Sdougm  * sa_init() during the API setup.
966185db85Sdougm  */
976185db85Sdougm 
986185db85Sdougm scfutilhandle_t *
99549ec3ffSdougm sa_scf_init(sa_handle_impl_t ihandle)
1006185db85Sdougm {
1016185db85Sdougm 	scfutilhandle_t *handle;
1026185db85Sdougm 
1036185db85Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1046185db85Sdougm 	if (scf_max_name_len <= 0)
1056185db85Sdougm 		scf_max_name_len = SA_MAX_NAME_LEN + 1;
1066185db85Sdougm 
1076185db85Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
108*25a68471Sdougm 	if (handle == NULL)
109*25a68471Sdougm 		return (handle);
110*25a68471Sdougm 
111549ec3ffSdougm 	ihandle->scfhandle = handle;
1126185db85Sdougm 	handle->scf_state = SCH_STATE_INITIALIZING;
1136185db85Sdougm 	handle->handle = scf_handle_create(SCF_VERSION);
114*25a68471Sdougm 	if (handle->handle == NULL) {
115*25a68471Sdougm 		free(handle);
116*25a68471Sdougm 		handle = NULL;
117*25a68471Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
118*25a68471Sdougm 		    scf_strerror(scf_error()));
119*25a68471Sdougm 		return (handle);
120*25a68471Sdougm 	}
121*25a68471Sdougm 	if (scf_handle_bind(handle->handle) != 0)
122*25a68471Sdougm 		goto err;
123*25a68471Sdougm 
1246185db85Sdougm 	handle->scope = scf_scope_create(handle->handle);
1256185db85Sdougm 	handle->service = scf_service_create(handle->handle);
1266185db85Sdougm 	handle->pg = scf_pg_create(handle->handle);
127a3351425Sdougm 
128*25a68471Sdougm 	/* Make sure we have sufficient SMF running */
1296185db85Sdougm 	handle->instance = scf_instance_create(handle->handle);
130a3351425Sdougm 	if (handle->scope == NULL || handle->service == NULL ||
131a3351425Sdougm 	    handle->pg == NULL || handle->instance == NULL)
132a3351425Sdougm 		goto err;
1336185db85Sdougm 	if (scf_handle_get_scope(handle->handle,
134*25a68471Sdougm 	    SCF_SCOPE_LOCAL, handle->scope) != 0)
1356185db85Sdougm 		goto err;
136*25a68471Sdougm 	if (scf_scope_get_service(handle->scope,
137*25a68471Sdougm 	    SA_GROUP_SVC_NAME, handle->service) != 0)
138*25a68471Sdougm 		goto err;
139*25a68471Sdougm 
1406185db85Sdougm 	handle->scf_state = SCH_STATE_INIT;
1416185db85Sdougm 	if (sa_get_instance(handle, "default") != SA_OK) {
1426185db85Sdougm 		char **protolist;
1436185db85Sdougm 		int numprotos, i;
1446185db85Sdougm 		sa_group_t defgrp;
145*25a68471Sdougm 		defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
1466185db85Sdougm 		if (defgrp != NULL) {
147*25a68471Sdougm 			numprotos = sa_get_protocols(
148*25a68471Sdougm 			    &protolist);
149*25a68471Sdougm 			for (i = 0; i < numprotos; i++)
1506185db85Sdougm 				(void) sa_create_optionset(defgrp,
1516185db85Sdougm 				    protolist[i]);
1526185db85Sdougm 			if (protolist != NULL)
1536185db85Sdougm 				free(protolist);
1546185db85Sdougm 		}
1556185db85Sdougm 	}
156*25a68471Sdougm 
1576185db85Sdougm 	return (handle);
1586185db85Sdougm 
159*25a68471Sdougm 	/* Error handling/unwinding */
1606185db85Sdougm err:
1616185db85Sdougm 	(void) sa_scf_fini(handle);
1626185db85Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
1636185db85Sdougm 	    scf_strerror(scf_error()));
1646185db85Sdougm 	return (NULL);
1656185db85Sdougm }
1666185db85Sdougm 
1676185db85Sdougm /*
1686185db85Sdougm  * get_scf_limit(name)
1696185db85Sdougm  *
1706185db85Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
1716185db85Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
1726185db85Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
1736185db85Sdougm  * (1024) so we have a reasonable default buffer size.
1746185db85Sdougm  */
1756185db85Sdougm static ssize_t
1766185db85Sdougm get_scf_limit(uint32_t name)
1776185db85Sdougm {
1786185db85Sdougm 	ssize_t vallen;
1796185db85Sdougm 
1806185db85Sdougm 	vallen = scf_limit(name);
1816185db85Sdougm 	if (vallen == (ssize_t)-1)
1826185db85Sdougm 		vallen = MAXPATHLEN;
1836185db85Sdougm 	return (vallen);
1846185db85Sdougm }
1856185db85Sdougm 
1866185db85Sdougm /*
1876185db85Sdougm  * skip_property(name)
1886185db85Sdougm  *
189*25a68471Sdougm  * Internal function to check to see if a property is an SMF magic
1906185db85Sdougm  * property that needs to be skipped.
1916185db85Sdougm  */
1926185db85Sdougm static int
1936185db85Sdougm skip_property(char *name)
1946185db85Sdougm {
1956185db85Sdougm 	int i;
1966185db85Sdougm 
1976185db85Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
1986185db85Sdougm 		if (strcmp(name, skip_props[i]) == 0)
1996185db85Sdougm 		return (1);
2006185db85Sdougm 	return (0);
2016185db85Sdougm }
2026185db85Sdougm 
2036185db85Sdougm /*
2046185db85Sdougm  * generate_unique_sharename(sharename)
2056185db85Sdougm  *
2066185db85Sdougm  * Shares are represented in SMF as property groups. Due to share
2076185db85Sdougm  * paths containing characters that are not allowed in SMF names and
2086185db85Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
2096185db85Sdougm  */
2106185db85Sdougm 
2116185db85Sdougm static void
2126185db85Sdougm generate_unique_sharename(char *sharename)
2136185db85Sdougm {
2146185db85Sdougm 	uuid_t uuid;
2156185db85Sdougm 
2166185db85Sdougm 	uuid_generate(uuid);
2176185db85Sdougm 	(void) strcpy(sharename, "S-");
2186185db85Sdougm 	uuid_unparse(uuid, sharename + 2);
2196185db85Sdougm }
2206185db85Sdougm 
2216185db85Sdougm /*
2226185db85Sdougm  * valid_protocol(proto)
2236185db85Sdougm  *
224*25a68471Sdougm  * Check to see if the specified protocol is a valid one for the
2256185db85Sdougm  * general sharemgr facility. We determine this by checking which
2266185db85Sdougm  * plugin protocols were found.
2276185db85Sdougm  */
2286185db85Sdougm 
2296185db85Sdougm static int
2306185db85Sdougm valid_protocol(char *proto)
2316185db85Sdougm {
2326185db85Sdougm 	struct sa_proto_plugin *plugin;
2336185db85Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
2346185db85Sdougm 	    plugin = plugin->plugin_next)
2356185db85Sdougm 		if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
2366185db85Sdougm 			return (1);
2376185db85Sdougm 	return (0);
2386185db85Sdougm }
2396185db85Sdougm 
2406185db85Sdougm /*
2416185db85Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2426185db85Sdougm  *
243*25a68471Sdougm  * Extract the name property group and create the specified type of
2446185db85Sdougm  * node on the provided group.  type will be optionset or security.
2456185db85Sdougm  */
2466185db85Sdougm 
2476185db85Sdougm static int
2486185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2496185db85Sdougm 			scf_propertygroup_t *pg,
2506185db85Sdougm 			char *nodetype, char *proto, char *sectype)
2516185db85Sdougm {
2526185db85Sdougm 	xmlNodePtr node;
2536185db85Sdougm 	scf_iter_t *iter;
2546185db85Sdougm 	scf_property_t *prop;
2556185db85Sdougm 	scf_value_t *value;
2566185db85Sdougm 	char *name;
2576185db85Sdougm 	char *valuestr;
2586185db85Sdougm 	ssize_t vallen;
2596185db85Sdougm 	int ret = SA_OK;
2606185db85Sdougm 
2616185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2626185db85Sdougm 
2636185db85Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
264*25a68471Sdougm 	if (node == NULL)
265*25a68471Sdougm 		return (ret);
266*25a68471Sdougm 
2676185db85Sdougm 	if (proto != NULL)
2686185db85Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2696185db85Sdougm 	if (sectype != NULL)
2706185db85Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
2716185db85Sdougm 	/*
272*25a68471Sdougm 	 * Have node to work with so iterate over the properties
2736185db85Sdougm 	 * in the pg and create option sub nodes.
2746185db85Sdougm 	 */
2756185db85Sdougm 	iter = scf_iter_create(handle->handle);
2766185db85Sdougm 	value = scf_value_create(handle->handle);
2776185db85Sdougm 	prop = scf_property_create(handle->handle);
2786185db85Sdougm 	name = malloc(scf_max_name_len);
2796185db85Sdougm 	valuestr = malloc(vallen);
2806185db85Sdougm 	/*
281*25a68471Sdougm 	 * Want to iterate through the properties and add them
2826185db85Sdougm 	 * to the base optionset.
2836185db85Sdougm 	 */
284*25a68471Sdougm 	if (iter == NULL || value == NULL || prop == NULL ||
285*25a68471Sdougm 	    valuestr == NULL || name == NULL) {
286*25a68471Sdougm 		ret = SA_NO_MEMORY;
287*25a68471Sdougm 		goto out;
288*25a68471Sdougm 	}
2896185db85Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
290*25a68471Sdougm 		/* Now iterate the properties in the group */
2916185db85Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
2926185db85Sdougm 			/* have a property */
2936185db85Sdougm 			if (scf_property_get_name(prop, name,
2946185db85Sdougm 			    scf_max_name_len) > 0) {
295*25a68471Sdougm 				sa_property_t saprop;
296*25a68471Sdougm 				/* Some properties are part of the framework */
2976185db85Sdougm 				if (skip_property(name))
2986185db85Sdougm 					continue;
299*25a68471Sdougm 				if (scf_property_get_value(prop, value) != 0)
300*25a68471Sdougm 					continue;
3016185db85Sdougm 				if (scf_value_get_astring(value, valuestr,
302*25a68471Sdougm 				    vallen) < 0)
303*25a68471Sdougm 					continue;
304*25a68471Sdougm 				saprop = sa_create_property(name, valuestr);
3056185db85Sdougm 				if (saprop != NULL) {
3066185db85Sdougm 					/*
307*25a68471Sdougm 					 * Since in SMF, don't
3086185db85Sdougm 					 * recurse. Use xmlAddChild
3096185db85Sdougm 					 * directly, instead.
3106185db85Sdougm 					 */
3116185db85Sdougm 					xmlAddChild(node,
3126185db85Sdougm 					    (xmlNodePtr) saprop);
3136185db85Sdougm 				}
3146185db85Sdougm 			}
3156185db85Sdougm 		}
3166185db85Sdougm 	}
317*25a68471Sdougm out:
3186185db85Sdougm 	/* cleanup to avoid memory leaks */
3196185db85Sdougm 	if (value != NULL)
3206185db85Sdougm 		scf_value_destroy(value);
3216185db85Sdougm 	if (iter != NULL)
3226185db85Sdougm 		scf_iter_destroy(iter);
3236185db85Sdougm 	if (prop != NULL)
3246185db85Sdougm 		scf_property_destroy(prop);
3256185db85Sdougm 	if (name != NULL)
3266185db85Sdougm 		free(name);
3276185db85Sdougm 	if (valuestr != NULL)
3286185db85Sdougm 		free(valuestr);
329*25a68471Sdougm 
3306185db85Sdougm 	return (ret);
3316185db85Sdougm }
3326185db85Sdougm 
3336185db85Sdougm /*
3346185db85Sdougm  * sa_extract_attrs(root, handle, instance)
3356185db85Sdougm  *
336*25a68471Sdougm  * Local function to extract the actual attributes/properties from the
3376185db85Sdougm  * property group of the service instance. These are the well known
3386185db85Sdougm  * attributes of "state" and "zfs". If additional attributes are
3396185db85Sdougm  * added, they should be added here.
3406185db85Sdougm  */
3416185db85Sdougm 
3426185db85Sdougm static void
3436185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3446185db85Sdougm 		    scf_instance_t *instance)
3456185db85Sdougm {
3466185db85Sdougm 	scf_property_t *prop;
3476185db85Sdougm 	scf_value_t *value;
3486185db85Sdougm 	char *valuestr;
3496185db85Sdougm 	ssize_t vallen;
3506185db85Sdougm 
3516185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3526185db85Sdougm 	prop = scf_property_create(handle->handle);
3536185db85Sdougm 	value = scf_value_create(handle->handle);
3546185db85Sdougm 	valuestr = malloc(vallen);
355*25a68471Sdougm 	if (prop == NULL || value == NULL || valuestr == NULL ||
356*25a68471Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
357*25a68471Sdougm 		goto out;
358*25a68471Sdougm 	}
3596185db85Sdougm 	/*
360*25a68471Sdougm 	 * Have a property group with desired name so now get
3616185db85Sdougm 	 * the known attributes.
3626185db85Sdougm 	 */
3636185db85Sdougm 	if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
364*25a68471Sdougm 		/* Found the property so get the value */
3656185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
366*25a68471Sdougm 			if (scf_value_get_astring(value, valuestr,
367*25a68471Sdougm 			    vallen) >= 0) {
3686185db85Sdougm 				xmlSetProp(root, (xmlChar *)"state",
3696185db85Sdougm 				    (xmlChar *)valuestr);
3706185db85Sdougm 			}
3716185db85Sdougm 		}
3726185db85Sdougm 	}
3736185db85Sdougm 	if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
374*25a68471Sdougm 		/* Found the property so get the value */
3756185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
376*25a68471Sdougm 			if (scf_value_get_astring(value, valuestr,
377*25a68471Sdougm 			    vallen) > 0) {
3786185db85Sdougm 				xmlSetProp(root, (xmlChar *)"zfs",
3796185db85Sdougm 				    (xmlChar *)valuestr);
3806185db85Sdougm 			}
3816185db85Sdougm 		}
3826185db85Sdougm 	}
383*25a68471Sdougm out:
3846185db85Sdougm 	if (valuestr != NULL)
3856185db85Sdougm 		free(valuestr);
3866185db85Sdougm 	if (value != NULL)
3876185db85Sdougm 		scf_value_destroy(value);
3886185db85Sdougm 	if (prop != NULL)
3896185db85Sdougm 		scf_property_destroy(prop);
3906185db85Sdougm }
3916185db85Sdougm 
3926185db85Sdougm /*
393*25a68471Sdougm  * List of known share attributes.
3946185db85Sdougm  */
3956185db85Sdougm 
3966185db85Sdougm static char *share_attr[] = {
3976185db85Sdougm 	"path",
3986185db85Sdougm 	"id",
3996185db85Sdougm 	"resource",
4006185db85Sdougm 	NULL,
4016185db85Sdougm };
4026185db85Sdougm 
4036185db85Sdougm static int
4046185db85Sdougm is_share_attr(char *name)
4056185db85Sdougm {
4066185db85Sdougm 	int i;
4076185db85Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
4086185db85Sdougm 		if (strcmp(name, share_attr[i]) == 0)
4096185db85Sdougm 			return (1);
4106185db85Sdougm 	return (0);
4116185db85Sdougm }
4126185db85Sdougm 
4136185db85Sdougm /*
4146185db85Sdougm  * sa_share_from_pgroup
4156185db85Sdougm  *
416*25a68471Sdougm  * Extract the share definition from the share property group. We do
4176185db85Sdougm  * some sanity checking to avoid bad data.
4186185db85Sdougm  *
4196185db85Sdougm  * Since this is only constructing the internal data structures, we
4206185db85Sdougm  * don't use the sa_* functions most of the time.
4216185db85Sdougm  */
4226185db85Sdougm void
4236185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4246185db85Sdougm 			scf_propertygroup_t *pg, char *id)
4256185db85Sdougm {
4266185db85Sdougm 	xmlNodePtr node;
4276185db85Sdougm 	char *name;
4286185db85Sdougm 	scf_iter_t *iter;
4296185db85Sdougm 	scf_property_t *prop;
4306185db85Sdougm 	scf_value_t *value;
4316185db85Sdougm 	ssize_t vallen;
4326185db85Sdougm 	char *valuestr;
4336185db85Sdougm 	int ret = SA_OK;
434f345c0beSdougm 	int have_path = 0;
4356185db85Sdougm 
4366185db85Sdougm 	/*
4376185db85Sdougm 	 * While preliminary check (starts with 'S') passed before
4386185db85Sdougm 	 * getting here. Need to make sure it is in ID syntax
4396185db85Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
4406185db85Sdougm 	 * pgroups.
4416185db85Sdougm 	 */
4426185db85Sdougm 	vallen = strlen(id);
4436185db85Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
4446185db85Sdougm 		uuid_t uuid;
445*25a68471Sdougm 		if (strncmp(id, SA_SHARE_PG_PREFIX,
446*25a68471Sdougm 		    SA_SHARE_PG_PREFIXLEN) != 0 ||
4476185db85Sdougm 		    uuid_parse(id + 2, uuid) < 0)
4486185db85Sdougm 			return;
4496185db85Sdougm 	} else {
4506185db85Sdougm 		return;
4516185db85Sdougm 	}
4526185db85Sdougm 
4536185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
4546185db85Sdougm 
4556185db85Sdougm 	iter = scf_iter_create(handle->handle);
4566185db85Sdougm 	value = scf_value_create(handle->handle);
4576185db85Sdougm 	prop = scf_property_create(handle->handle);
4586185db85Sdougm 	name = malloc(scf_max_name_len);
4596185db85Sdougm 	valuestr = malloc(vallen);
4606185db85Sdougm 
4616185db85Sdougm 	/*
462*25a68471Sdougm 	 * Construct the share XML node. It is similar to sa_add_share
4636185db85Sdougm 	 * but never changes the repository. Also, there won't be any
4646185db85Sdougm 	 * ZFS or transient shares.  Root will be the group it is
4656185db85Sdougm 	 * associated with.
4666185db85Sdougm 	 */
4676185db85Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
4686185db85Sdougm 	if (node != NULL) {
4696185db85Sdougm 		/*
470*25a68471Sdougm 		 * Make sure the UUID part of the property group is
4716185db85Sdougm 		 * stored in the share "id" property. We use this
4726185db85Sdougm 		 * later.
4736185db85Sdougm 		 */
4746185db85Sdougm 		xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
4756185db85Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
4766185db85Sdougm 	}
4776185db85Sdougm 
478*25a68471Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
479*25a68471Sdougm 		goto out;
480*25a68471Sdougm 
481*25a68471Sdougm 	/* Iterate over the share pg properties */
482*25a68471Sdougm 	if (scf_iter_pg_properties(iter, pg) != 0)
483*25a68471Sdougm 		goto out;
484*25a68471Sdougm 
4856185db85Sdougm 	while (scf_iter_next_property(iter, prop) > 0) {
4866185db85Sdougm 		ret = SA_SYSTEM_ERR; /* assume the worst */
487*25a68471Sdougm 		if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
4886185db85Sdougm 			if (scf_property_get_value(prop, value) == 0) {
4896185db85Sdougm 				if (scf_value_get_astring(value, valuestr,
4906185db85Sdougm 				    vallen) >= 0) {
4916185db85Sdougm 					ret = SA_OK;
4926185db85Sdougm 				}
4936185db85Sdougm 			}
4946185db85Sdougm 		}
4956185db85Sdougm 		if (ret == SA_OK) {
496f345c0beSdougm 			/*
497*25a68471Sdougm 			 * Check that we have the "path" property in
498f345c0beSdougm 			 * name. The string in name will always be nul
499f345c0beSdougm 			 * terminated if scf_property_get_name()
500f345c0beSdougm 			 * succeeded.
501f345c0beSdougm 			 */
502f345c0beSdougm 			if (strcmp(name, "path") == 0)
503f345c0beSdougm 				have_path = 1;
5046185db85Sdougm 			if (is_share_attr(name)) {
5056185db85Sdougm 				/*
506*25a68471Sdougm 				 * If a share attr, then simple -
5076185db85Sdougm 				 * usually path and resource name
5086185db85Sdougm 				 */
5096185db85Sdougm 				xmlSetProp(node, (xmlChar *)name,
5106185db85Sdougm 				    (xmlChar *)valuestr);
5116185db85Sdougm 			} else {
5126185db85Sdougm 				if (strcmp(name, "description") == 0) {
513*25a68471Sdougm 					/* We have a description node */
5146185db85Sdougm 					xmlNodePtr desc;
5156185db85Sdougm 					desc = xmlNewChild(node, NULL,
516*25a68471Sdougm 					    (xmlChar *)"description", NULL);
5176185db85Sdougm 					if (desc != NULL)
5186185db85Sdougm 						xmlNodeSetContent(desc,
5196185db85Sdougm 						    (xmlChar *)valuestr);
5206185db85Sdougm 				}
5216185db85Sdougm 			}
5226185db85Sdougm 		}
5236185db85Sdougm 	}
524*25a68471Sdougm out:
525f345c0beSdougm 	/*
526*25a68471Sdougm 	 * A share without a path is broken so we want to not include
527f345c0beSdougm 	 * these.  They shouldn't happen but if you kill a sharemgr in
528f345c0beSdougm 	 * the process of creating a share, it could happen.  They
529f345c0beSdougm 	 * should be harmless.  It is also possible that another
530f345c0beSdougm 	 * sharemgr is running and in the process of creating a share.
531f345c0beSdougm 	 */
532f345c0beSdougm 	if (have_path == 0 && node != NULL) {
533f345c0beSdougm 		xmlUnlinkNode(node);
534f345c0beSdougm 		xmlFreeNode(node);
535f345c0beSdougm 	}
5366185db85Sdougm 	if (name != NULL)
5376185db85Sdougm 		free(name);
5386185db85Sdougm 	if (valuestr != NULL)
5396185db85Sdougm 		free(valuestr);
5406185db85Sdougm 	if (value != NULL)
5416185db85Sdougm 		scf_value_destroy(value);
5426185db85Sdougm 	if (iter != NULL)
5436185db85Sdougm 		scf_iter_destroy(iter);
5446185db85Sdougm 	if (prop != NULL)
5456185db85Sdougm 		scf_property_destroy(prop);
5466185db85Sdougm }
5476185db85Sdougm 
5486185db85Sdougm /*
5496185db85Sdougm  * find_share_by_id(shareid)
5506185db85Sdougm  *
5516185db85Sdougm  * Search all shares in all groups until we find the share represented
5526185db85Sdougm  * by "id".
5536185db85Sdougm  */
5546185db85Sdougm 
5556185db85Sdougm static sa_share_t
556549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid)
5576185db85Sdougm {
5586185db85Sdougm 	sa_group_t group;
5596185db85Sdougm 	sa_share_t share = NULL;
5606185db85Sdougm 	char *id = NULL;
5616185db85Sdougm 	int done = 0;
5626185db85Sdougm 
563*25a68471Sdougm 	for (group = sa_get_group(handle, NULL);
564*25a68471Sdougm 	    group != NULL && !done;
5656185db85Sdougm 	    group = sa_get_next_group(group)) {
566*25a68471Sdougm 		for (share = sa_get_share(group, NULL);
567*25a68471Sdougm 		    share != NULL;
5686185db85Sdougm 		    share = sa_get_next_share(share)) {
5696185db85Sdougm 			id = sa_get_share_attr(share, "id");
5706185db85Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
5716185db85Sdougm 				sa_free_attr_string(id);
5726185db85Sdougm 				id = NULL;
5736185db85Sdougm 				done++;
5746185db85Sdougm 				break;
5756185db85Sdougm 			}
5766185db85Sdougm 			if (id != NULL) {
5776185db85Sdougm 				sa_free_attr_string(id);
5786185db85Sdougm 				id = NULL;
5796185db85Sdougm 			}
5806185db85Sdougm 		}
5816185db85Sdougm 	}
5826185db85Sdougm 	return (share);
5836185db85Sdougm }
5846185db85Sdougm 
5856185db85Sdougm /*
5866185db85Sdougm  * sa_share_props_from_pgroup(root, handle, pg, id)
5876185db85Sdougm  *
588*25a68471Sdougm  * Extract share properties from the SMF property group. More sanity
5896185db85Sdougm  * checks are done and the share object is created. We ignore some
5906185db85Sdougm  * errors that could exist in the repository and only worry about
5916185db85Sdougm  * property groups that validate in naming.
5926185db85Sdougm  */
5936185db85Sdougm 
5946185db85Sdougm static int
5956185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
596549ec3ffSdougm 			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
5976185db85Sdougm {
5986185db85Sdougm 	xmlNodePtr node;
599*25a68471Sdougm 	char *name = NULL;
600*25a68471Sdougm 	scf_iter_t *iter = NULL;
601*25a68471Sdougm 	scf_property_t *prop = NULL;
602*25a68471Sdougm 	scf_value_t *value = NULL;
6036185db85Sdougm 	ssize_t vallen;
604*25a68471Sdougm 	char *valuestr = NULL;
6056185db85Sdougm 	int ret = SA_OK;
6066185db85Sdougm 	char *sectype = NULL;
6076185db85Sdougm 	char *proto;
6086185db85Sdougm 	sa_share_t share;
609*25a68471Sdougm 	uuid_t uuid;
6106185db85Sdougm 
6116185db85Sdougm 	/*
6126185db85Sdougm 	 * While preliminary check (starts with 'S') passed before
6136185db85Sdougm 	 * getting here. Need to make sure it is in ID syntax
6146185db85Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
6156185db85Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
6166185db85Sdougm 	 * characters, it is likely one of the protocol/security
6176185db85Sdougm 	 * versions.
6186185db85Sdougm 	 */
6196185db85Sdougm 	vallen = strlen(id);
620*25a68471Sdougm 	if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
621*25a68471Sdougm 		/*
622*25a68471Sdougm 		 * It is ok to not have what we thought since someone might
623*25a68471Sdougm 		 * have added a name via SMF.
624*25a68471Sdougm 		 */
625*25a68471Sdougm 		return (ret);
626*25a68471Sdougm 	}
6276185db85Sdougm 	if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
6286185db85Sdougm 		proto = strchr(id, '_');
6296185db85Sdougm 		if (proto == NULL)
6306185db85Sdougm 			return (ret);
6316185db85Sdougm 		*proto++ = '\0';
6326185db85Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
6336185db85Sdougm 			return (ret);
6346185db85Sdougm 		/*
6356185db85Sdougm 		 * probably a legal optionset so check a few more
6366185db85Sdougm 		 * syntax points below.
6376185db85Sdougm 		 */
6386185db85Sdougm 		if (*proto == '\0') {
6396185db85Sdougm 			/* not a valid proto (null) */
6406185db85Sdougm 			return (ret);
6416185db85Sdougm 		}
6426185db85Sdougm 		sectype = strchr(proto, '_');
6436185db85Sdougm 		if (sectype != NULL)
6446185db85Sdougm 			*sectype++ = '\0';
6456185db85Sdougm 		if (!valid_protocol(proto))
6466185db85Sdougm 			return (ret);
6476185db85Sdougm 	}
6486185db85Sdougm 
6496185db85Sdougm 	/*
650*25a68471Sdougm 	 * To get here, we have a valid protocol and possibly a
6516185db85Sdougm 	 * security. We now have to find the share that it is really
6526185db85Sdougm 	 * associated with. The "id" portion of the pgroup name will
6536185db85Sdougm 	 * match.
6546185db85Sdougm 	 */
6556185db85Sdougm 
656549ec3ffSdougm 	share = find_share_by_id(sahandle, id);
6576185db85Sdougm 	if (share == NULL)
6586185db85Sdougm 		return (SA_BAD_PATH);
6596185db85Sdougm 
6606185db85Sdougm 	root = (xmlNodePtr)share;
6616185db85Sdougm 
6626185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
6636185db85Sdougm 
664*25a68471Sdougm 	if (sectype == NULL)
665*25a68471Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
666*25a68471Sdougm 	else {
667*25a68471Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
668*25a68471Sdougm 		if (node != NULL)
669*25a68471Sdougm 			xmlSetProp(node, (xmlChar *)"sectype",
670*25a68471Sdougm 			    (xmlChar *)sectype);
671*25a68471Sdougm 	}
672*25a68471Sdougm 	if (node == NULL) {
673*25a68471Sdougm 		ret = SA_NO_MEMORY;
674*25a68471Sdougm 		goto out;
675*25a68471Sdougm 	}
676*25a68471Sdougm 
677*25a68471Sdougm 	xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
678*25a68471Sdougm 	/* now find the properties */
6796185db85Sdougm 	iter = scf_iter_create(handle->handle);
6806185db85Sdougm 	value = scf_value_create(handle->handle);
6816185db85Sdougm 	prop = scf_property_create(handle->handle);
6826185db85Sdougm 	name = malloc(scf_max_name_len);
6836185db85Sdougm 	valuestr = malloc(vallen);
6846185db85Sdougm 
685*25a68471Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
686*25a68471Sdougm 		goto out;
687*25a68471Sdougm 
688*25a68471Sdougm 	/* Iterate over the share pg properties */
6896185db85Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
6906185db85Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
6916185db85Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
6926185db85Sdougm 			if (scf_property_get_name(prop, name,
6936185db85Sdougm 			    scf_max_name_len) > 0) {
6946185db85Sdougm 				if (scf_property_get_value(prop, value) == 0) {
695*25a68471Sdougm 					if (scf_value_get_astring(value,
696*25a68471Sdougm 					    valuestr, vallen) >= 0) {
6976185db85Sdougm 						ret = SA_OK;
6986185db85Sdougm 					}
6996185db85Sdougm 				}
7006185db85Sdougm 			} else {
7016185db85Sdougm 				ret = SA_SYSTEM_ERR;
7026185db85Sdougm 			}
7036185db85Sdougm 			if (ret == SA_OK) {
7046185db85Sdougm 				sa_property_t prop;
7056185db85Sdougm 				prop = sa_create_property(name, valuestr);
7066185db85Sdougm 				if (prop != NULL)
7076185db85Sdougm 					prop = (sa_property_t)xmlAddChild(node,
7086185db85Sdougm 					    (xmlNodePtr)prop);
7096185db85Sdougm 				else
7106185db85Sdougm 					ret = SA_NO_MEMORY;
7116185db85Sdougm 			}
7126185db85Sdougm 		}
7136185db85Sdougm 	} else {
7146185db85Sdougm 		ret = SA_SYSTEM_ERR;
7156185db85Sdougm 	}
716*25a68471Sdougm out:
7176185db85Sdougm 	if (iter != NULL)
7186185db85Sdougm 		scf_iter_destroy(iter);
7196185db85Sdougm 	if (value != NULL)
7206185db85Sdougm 		scf_value_destroy(value);
7216185db85Sdougm 	if (prop != NULL)
7226185db85Sdougm 		scf_property_destroy(prop);
7236185db85Sdougm 	if (name != NULL)
7246185db85Sdougm 		free(name);
7256185db85Sdougm 	if (valuestr != NULL)
7266185db85Sdougm 		free(valuestr);
7276185db85Sdougm 	return (ret);
7286185db85Sdougm }
7296185db85Sdougm 
7306185db85Sdougm /*
7316185db85Sdougm  * sa_extract_group(root, handle, instance)
7326185db85Sdougm  *
733*25a68471Sdougm  * Get the config info for this instance of a group and create the XML
7346185db85Sdougm  * subtree from it.
7356185db85Sdougm  */
7366185db85Sdougm 
7376185db85Sdougm static int
7386185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
739549ec3ffSdougm 			scf_instance_t *instance, sa_handle_t sahandle)
7406185db85Sdougm {
7416185db85Sdougm 	char *buff;
7426185db85Sdougm 	xmlNodePtr node;
7436185db85Sdougm 	scf_iter_t *iter;
7446185db85Sdougm 	char *proto;
7456185db85Sdougm 	char *sectype;
7466185db85Sdougm 	int have_shares = 0;
7476185db85Sdougm 	int has_proto = 0;
7486185db85Sdougm 	int is_default = 0;
7496185db85Sdougm 	int ret = SA_OK;
7506185db85Sdougm 	int err;
7516185db85Sdougm 
7526185db85Sdougm 	buff = malloc(scf_max_name_len);
753*25a68471Sdougm 	if (buff == NULL)
754*25a68471Sdougm 		return (SA_NO_MEMORY);
755*25a68471Sdougm 
7566185db85Sdougm 	iter = scf_iter_create(handle->handle);
757*25a68471Sdougm 	if (iter == NULL) {
758*25a68471Sdougm 		ret = SA_NO_MEMORY;
759*25a68471Sdougm 		goto out;
760*25a68471Sdougm 	}
761*25a68471Sdougm 
762*25a68471Sdougm 	if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
7636185db85Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
764*25a68471Sdougm 		if (node == NULL) {
765*25a68471Sdougm 			ret = SA_NO_MEMORY;
766*25a68471Sdougm 			goto out;
767*25a68471Sdougm 		}
7686185db85Sdougm 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
7696185db85Sdougm 		if (strcmp(buff, "default") == 0)
7706185db85Sdougm 			is_default++;
771*25a68471Sdougm 
7726185db85Sdougm 		sa_extract_attrs(node, handle, instance);
7736185db85Sdougm 		/*
7746185db85Sdougm 		 * Iterate through all the property groups
7756185db85Sdougm 		 * looking for those with security or
7766185db85Sdougm 		 * optionset prefixes. The names of the
7776185db85Sdougm 		 * matching pgroups are parsed to get the
7786185db85Sdougm 		 * protocol, and for security, the sectype.
7796185db85Sdougm 		 * Syntax is as follows:
7806185db85Sdougm 		 *    optionset | optionset_<proto>
7816185db85Sdougm 		 *    security_default | security_<proto>_<sectype>
7826185db85Sdougm 		 * "operation" is handled by
7836185db85Sdougm 		 * sa_extract_attrs().
7846185db85Sdougm 		 */
785*25a68471Sdougm 		if (scf_iter_instance_pgs(iter, instance) != 0) {
786*25a68471Sdougm 			ret = SA_NO_MEMORY;
787*25a68471Sdougm 			goto out;
788*25a68471Sdougm 		}
7896185db85Sdougm 		while (scf_iter_next_pg(iter, handle->pg) > 0) {
790*25a68471Sdougm 			/* Have a pgroup so sort it out */
7916185db85Sdougm 			ret = scf_pg_get_name(handle->pg, buff,
7926185db85Sdougm 			    scf_max_name_len);
7936185db85Sdougm 			if (ret  > 0) {
7946185db85Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
7956185db85Sdougm 					sa_share_from_pgroup(node, handle,
796*25a68471Sdougm 					    handle->pg, buff);
7976185db85Sdougm 					have_shares++;
7986185db85Sdougm 				} else if (strncmp(buff, "optionset", 9) ==
7996185db85Sdougm 				    0) {
8006185db85Sdougm 					char *nodetype = "optionset";
801*25a68471Sdougm 					/* Have an optionset */
8026185db85Sdougm 					sectype = NULL;
8036185db85Sdougm 					proto = strchr(buff, '_');
8046185db85Sdougm 					if (proto != NULL) {
8056185db85Sdougm 						*proto++ = '\0';
8066185db85Sdougm 						sectype = strchr(proto, '_');
8076185db85Sdougm 						if (sectype != NULL) {
8086185db85Sdougm 							*sectype++ = '\0';
8096185db85Sdougm 							nodetype = "security";
8106185db85Sdougm 						}
8116185db85Sdougm 					}
8126185db85Sdougm 					ret = sa_extract_pgroup(node, handle,
813*25a68471Sdougm 					    handle->pg, nodetype, proto,
814*25a68471Sdougm 					    sectype);
8156185db85Sdougm 					has_proto++;
816*25a68471Sdougm 				} else if (strncmp(buff, "security", 8) == 0) {
8176185db85Sdougm 					/*
818*25a68471Sdougm 					 * Have a security (note that
8196185db85Sdougm 					 * this should change in the
8206185db85Sdougm 					 * future)
8216185db85Sdougm 					 */
8226185db85Sdougm 					proto = strchr(buff, '_');
8236185db85Sdougm 					sectype = NULL;
8246185db85Sdougm 					if (proto != NULL) {
8256185db85Sdougm 						*proto++ = '\0';
8266185db85Sdougm 						sectype = strchr(proto, '_');
8276185db85Sdougm 						if (sectype != NULL)
8286185db85Sdougm 							*sectype++ = '\0';
829*25a68471Sdougm 						if (strcmp(proto, "default") ==
830*25a68471Sdougm 						    0)
8316185db85Sdougm 							proto = NULL;
8326185db85Sdougm 					}
8336185db85Sdougm 					ret = sa_extract_pgroup(node, handle,
834*25a68471Sdougm 					    handle->pg, "security", proto,
8356185db85Sdougm 					    sectype);
8366185db85Sdougm 					has_proto++;
8376185db85Sdougm 				}
838*25a68471Sdougm 				/* Ignore everything else */
8396185db85Sdougm 			}
8406185db85Sdougm 		}
8416185db85Sdougm 		/*
8426185db85Sdougm 		 * Make sure we have a valid default group.
8436185db85Sdougm 		 * On first boot, default won't have any
8446185db85Sdougm 		 * protocols defined and won't be enabled (but
8456185db85Sdougm 		 * should be).
8466185db85Sdougm 		 */
8476185db85Sdougm 		if (is_default) {
8486185db85Sdougm 			char *state = sa_get_group_attr((sa_group_t)node,
8496185db85Sdougm 			    "state");
8506185db85Sdougm 			char **protos;
8516185db85Sdougm 			int numprotos;
8526185db85Sdougm 			int i;
8536185db85Sdougm 
8546185db85Sdougm 			if (state == NULL) {
8556185db85Sdougm 				/* set attribute to enabled */
8566185db85Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
857*25a68471Sdougm 				    "state", "enabled");
858*25a68471Sdougm 				/* We can assume no protocols */
8596185db85Sdougm 				numprotos = sa_get_protocols(&protos);
8606185db85Sdougm 				for (i = 0; i < numprotos; i++)
861*25a68471Sdougm 					(void) sa_create_optionset(
862*25a68471Sdougm 					    (sa_group_t)node, protos[i]);
8636185db85Sdougm 				if (numprotos > 0)
8646185db85Sdougm 					free(protos);
8656185db85Sdougm 			} else {
8666185db85Sdougm 				sa_free_attr_string(state);
8676185db85Sdougm 			}
8686185db85Sdougm 		}
869*25a68471Sdougm 		/* Do a second pass if shares were found */
870*25a68471Sdougm 		if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
8716185db85Sdougm 			while (scf_iter_next_pg(iter, handle->pg) > 0) {
8726185db85Sdougm 				/*
873*25a68471Sdougm 				 * Have a pgroup so see if it is a
8746185db85Sdougm 				 * share optionset
8756185db85Sdougm 				 */
8766185db85Sdougm 				err = scf_pg_get_name(handle->pg, buff,
8776185db85Sdougm 				    scf_max_name_len);
878*25a68471Sdougm 				if (err  <= 0)
879*25a68471Sdougm 					continue;
8806185db85Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
8816185db85Sdougm 					ret = sa_share_props_from_pgroup(node,
882*25a68471Sdougm 					    handle, handle->pg, buff,
883*25a68471Sdougm 					    sahandle);
8846185db85Sdougm 				}
8856185db85Sdougm 			}
8866185db85Sdougm 		}
8876185db85Sdougm 	}
888*25a68471Sdougm out:
8896185db85Sdougm 	if (iter != NULL)
8906185db85Sdougm 		scf_iter_destroy(iter);
8916185db85Sdougm 	if (buff != NULL)
8926185db85Sdougm 		free(buff);
8936185db85Sdougm 	return (ret);
8946185db85Sdougm }
8956185db85Sdougm 
8966185db85Sdougm /*
8976185db85Sdougm  * sa_extract_defaults(root, handle, instance)
8986185db85Sdougm  *
899*25a68471Sdougm  * Local function to find the default properties that live in the
9006185db85Sdougm  * default instance's "operation" proprerty group.
9016185db85Sdougm  */
9026185db85Sdougm 
9036185db85Sdougm static void
9046185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
9056185db85Sdougm 		    scf_instance_t *instance)
9066185db85Sdougm {
9076185db85Sdougm 	xmlNodePtr node;
9086185db85Sdougm 	scf_property_t *prop;
9096185db85Sdougm 	scf_value_t *value;
9106185db85Sdougm 	char *valuestr;
9116185db85Sdougm 	ssize_t vallen;
9126185db85Sdougm 
9136185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
9146185db85Sdougm 	prop = scf_property_create(handle->handle);
9156185db85Sdougm 	value = scf_value_create(handle->handle);
9166185db85Sdougm 	valuestr = malloc(vallen);
917*25a68471Sdougm 
918*25a68471Sdougm 	if (prop == NULL || value == NULL || vallen == 0 ||
919*25a68471Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0)
920*25a68471Sdougm 		goto out;
921*25a68471Sdougm 
922*25a68471Sdougm 	if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
923*25a68471Sdougm 		goto out;
924*25a68471Sdougm 
925*25a68471Sdougm 	/* Found the property so get the value */
9266185db85Sdougm 	if (scf_property_get_value(prop, value) == 0) {
9276185db85Sdougm 		if (scf_value_get_astring(value, valuestr, vallen) > 0) {
9286185db85Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
9296185db85Sdougm 			    NULL);
9306185db85Sdougm 			if (node != NULL) {
9316185db85Sdougm 				xmlSetProp(node, (xmlChar *)"timestamp",
9326185db85Sdougm 				    (xmlChar *)valuestr);
9336185db85Sdougm 				xmlSetProp(node, (xmlChar *)"path",
9346185db85Sdougm 				    (xmlChar *)SA_LEGACY_DFSTAB);
9356185db85Sdougm 			}
9366185db85Sdougm 		}
9376185db85Sdougm 	}
938*25a68471Sdougm out:
9396185db85Sdougm 	if (valuestr != NULL)
9406185db85Sdougm 		free(valuestr);
9416185db85Sdougm 	if (value != NULL)
9426185db85Sdougm 		scf_value_destroy(value);
9436185db85Sdougm 	if (prop != NULL)
9446185db85Sdougm 		scf_property_destroy(prop);
9456185db85Sdougm }
9466185db85Sdougm 
9476185db85Sdougm 
9486185db85Sdougm /*
949549ec3ffSdougm  * sa_get_config(handle, root, doc, sahandlec)
9506185db85Sdougm  *
951*25a68471Sdougm  * Walk the SMF repository for /network/shares/group and find all the
9526185db85Sdougm  * instances. These become group names.  Then add the XML structure
9536185db85Sdougm  * below the groups based on property groups and properties.
9546185db85Sdougm  */
9556185db85Sdougm int
9561d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
9576185db85Sdougm {
9586185db85Sdougm 	int ret = SA_OK;
9596185db85Sdougm 	scf_instance_t *instance;
9606185db85Sdougm 	scf_iter_t *iter;
9616185db85Sdougm 	char buff[BUFSIZ * 2];
9626185db85Sdougm 
9636185db85Sdougm 	instance = scf_instance_create(handle->handle);
9646185db85Sdougm 	iter = scf_iter_create(handle->handle);
9651d1813a7Sdougm 	if (instance != NULL && iter != NULL) {
9666185db85Sdougm 		if ((ret = scf_iter_service_instances(iter,
9676185db85Sdougm 		    handle->service)) == 0) {
9686185db85Sdougm 			while ((ret = scf_iter_next_instance(iter,
9696185db85Sdougm 			    instance)) > 0) {
9706185db85Sdougm 				if (scf_instance_get_name(instance, buff,
9716185db85Sdougm 				    sizeof (buff)) > 0) {
9726185db85Sdougm 					if (strcmp(buff, "default") == 0)
973*25a68471Sdougm 						sa_extract_defaults(root,
974*25a68471Sdougm 						    handle, instance);
975*25a68471Sdougm 					ret = sa_extract_group(root, handle,
976*25a68471Sdougm 					    instance, sahandle);
9776185db85Sdougm 				}
9786185db85Sdougm 			}
9796185db85Sdougm 		}
9806185db85Sdougm 	}
9811d1813a7Sdougm 
982*25a68471Sdougm 	/* Always cleanup these */
9836185db85Sdougm 	if (instance != NULL)
9846185db85Sdougm 		scf_instance_destroy(instance);
9856185db85Sdougm 	if (iter != NULL)
9866185db85Sdougm 		scf_iter_destroy(iter);
9876185db85Sdougm 	return (ret);
9886185db85Sdougm }
9896185db85Sdougm 
9906185db85Sdougm /*
9916185db85Sdougm  * sa_get_instance(handle, instance)
9926185db85Sdougm  *
993*25a68471Sdougm  * Get the instance of the group service. This is actually the
9946185db85Sdougm  * specific group name. The instance is needed for all property and
9956185db85Sdougm  * control operations.
9966185db85Sdougm  */
9976185db85Sdougm 
9986185db85Sdougm int
9996185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
10006185db85Sdougm {
10016185db85Sdougm 	if (scf_service_get_instance(handle->service, instname,
10026185db85Sdougm 	    handle->instance) != 0) {
10036185db85Sdougm 		return (SA_NO_SUCH_GROUP);
10046185db85Sdougm 	}
10056185db85Sdougm 	return (SA_OK);
10066185db85Sdougm }
10076185db85Sdougm 
10086185db85Sdougm /*
10096185db85Sdougm  * sa_create_instance(handle, instname)
10106185db85Sdougm  *
10116185db85Sdougm  * Create a new SMF service instance. There can only be one with a
10126185db85Sdougm  * given name.
10136185db85Sdougm  */
10146185db85Sdougm 
10156185db85Sdougm int
10166185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
10176185db85Sdougm {
10186185db85Sdougm 	int ret = SA_OK;
10196185db85Sdougm 	char instance[SA_GROUP_INST_LEN];
10206185db85Sdougm 	if (scf_service_add_instance(handle->service, instname,
10216185db85Sdougm 	    handle->instance) != 0) {
10226185db85Sdougm 	/* better error returns need to be added based on real error */
10236185db85Sdougm 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
10246185db85Sdougm 			ret = SA_NO_PERMISSION;
10256185db85Sdougm 		else
10266185db85Sdougm 			ret = SA_DUPLICATE_NAME;
10276185db85Sdougm 	} else {
10286185db85Sdougm 		/* have the service created, so enable it */
10296185db85Sdougm 		(void) snprintf(instance, sizeof (instance), "%s:%s",
10306185db85Sdougm 		    SA_SVC_FMRI_BASE, instname);
10316185db85Sdougm 		(void) smf_enable_instance(instance, 0);
10326185db85Sdougm 	}
10336185db85Sdougm 	return (ret);
10346185db85Sdougm }
10356185db85Sdougm 
10366185db85Sdougm /*
10376185db85Sdougm  * sa_delete_instance(handle, instname)
10386185db85Sdougm  *
10396185db85Sdougm  * When a group goes away, we also remove the service instance.
10406185db85Sdougm  */
10416185db85Sdougm 
10426185db85Sdougm int
10436185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
10446185db85Sdougm {
10456185db85Sdougm 	int ret;
10466185db85Sdougm 
10476185db85Sdougm 	if (strcmp(instname, "default") == 0) {
10486185db85Sdougm 		ret = SA_NO_PERMISSION;
10496185db85Sdougm 	} else {
10506185db85Sdougm 		if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
10516185db85Sdougm 			if (scf_instance_delete(handle->instance) != 0)
10526185db85Sdougm 				/* need better analysis */
10536185db85Sdougm 				ret = SA_NO_PERMISSION;
10546185db85Sdougm 		}
10556185db85Sdougm 	}
10566185db85Sdougm 	return (ret);
10576185db85Sdougm }
10586185db85Sdougm 
10596185db85Sdougm /*
10606185db85Sdougm  * sa_create_pgroup(handle, pgroup)
10616185db85Sdougm  *
10626185db85Sdougm  * create a new property group
10636185db85Sdougm  */
10646185db85Sdougm 
10656185db85Sdougm int
10666185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
10676185db85Sdougm {
10686185db85Sdougm 	int ret = SA_OK;
10696185db85Sdougm 	/*
1070*25a68471Sdougm 	 * Only create a handle if it doesn't exist. It is ok to exist
10716185db85Sdougm 	 * since the pg handle will be set as a side effect.
10726185db85Sdougm 	 */
1073*25a68471Sdougm 	if (handle->pg == NULL)
10746185db85Sdougm 		handle->pg = scf_pg_create(handle->handle);
1075*25a68471Sdougm 
10766185db85Sdougm 	/*
1077*25a68471Sdougm 	 * If the pgroup exists, we are done. If it doesn't, then we
10786185db85Sdougm 	 * need to actually add one to the service instance.
10796185db85Sdougm 	 */
10806185db85Sdougm 	if (scf_instance_get_pg(handle->instance,
10816185db85Sdougm 	    pgroup, handle->pg) != 0) {
1082*25a68471Sdougm 		/* Doesn't exist so create one */
10836185db85Sdougm 		if (scf_instance_add_pg(handle->instance, pgroup,
1084*25a68471Sdougm 		    SCF_GROUP_APPLICATION, 0, handle->pg) != 0) {
10856185db85Sdougm 			switch (scf_error()) {
10866185db85Sdougm 			case SCF_ERROR_PERMISSION_DENIED:
10876185db85Sdougm 				ret = SA_NO_PERMISSION;
10886185db85Sdougm 				break;
10896185db85Sdougm 			default:
10906185db85Sdougm 				ret = SA_SYSTEM_ERR;
10916185db85Sdougm 				break;
10926185db85Sdougm 			}
10936185db85Sdougm 		}
10946185db85Sdougm 	}
10956185db85Sdougm 	return (ret);
10966185db85Sdougm }
10976185db85Sdougm 
10986185db85Sdougm /*
10996185db85Sdougm  * sa_delete_pgroup(handle, pgroup)
11006185db85Sdougm  *
1101*25a68471Sdougm  * Remove the property group from the current instance of the service,
11026185db85Sdougm  * but only if it actually exists.
11036185db85Sdougm  */
11046185db85Sdougm 
11056185db85Sdougm int
11066185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
11076185db85Sdougm {
11086185db85Sdougm 	int ret = SA_OK;
11096185db85Sdougm 	/*
1110*25a68471Sdougm 	 * Only delete if it does exist.
11116185db85Sdougm 	 */
1112*25a68471Sdougm 	if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
11136185db85Sdougm 		/* does exist so delete it */
1114*25a68471Sdougm 		if (scf_pg_delete(handle->pg) != 0)
11156185db85Sdougm 			ret = SA_SYSTEM_ERR;
11166185db85Sdougm 	} else {
11176185db85Sdougm 		ret = SA_SYSTEM_ERR;
11186185db85Sdougm 	}
11196185db85Sdougm 	if (ret == SA_SYSTEM_ERR &&
11206185db85Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
11216185db85Sdougm 		ret = SA_NO_PERMISSION;
11226185db85Sdougm 	}
11236185db85Sdougm 	return (ret);
11246185db85Sdougm }
11256185db85Sdougm 
11266185db85Sdougm /*
11276185db85Sdougm  * sa_start_transaction(handle, pgroup)
11286185db85Sdougm  *
11296185db85Sdougm  * Start an SMF transaction so we can deal with properties. it would
11306185db85Sdougm  * be nice to not have to expose this, but we have to in order to
11316185db85Sdougm  * optimize.
11326185db85Sdougm  *
11336185db85Sdougm  * Basic model is to hold the transaction in the handle and allow
11346185db85Sdougm  * property adds/deletes/updates to be added then close the
11356185db85Sdougm  * transaction (or abort).  There may eventually be a need to handle
11366185db85Sdougm  * other types of transaction mechanisms but we don't do that now.
11376185db85Sdougm  *
11386185db85Sdougm  * An sa_start_transaction must be followed by either an
11396185db85Sdougm  * sa_end_transaction or sa_abort_transaction before another
11406185db85Sdougm  * sa_start_transaction can be done.
11416185db85Sdougm  */
11426185db85Sdougm 
11436185db85Sdougm int
11446185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
11456185db85Sdougm {
11466185db85Sdougm 	int ret = SA_OK;
11476185db85Sdougm 	/*
1148*25a68471Sdougm 	 * Lookup the property group and create it if it doesn't already
11496185db85Sdougm 	 * exist.
11506185db85Sdougm 	 */
11516185db85Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
11526185db85Sdougm 		ret = sa_create_pgroup(handle, propgroup);
11536185db85Sdougm 		if (ret == SA_OK) {
11546185db85Sdougm 			handle->trans = scf_transaction_create(handle->handle);
11556185db85Sdougm 			if (handle->trans != NULL) {
1156*25a68471Sdougm 				if (scf_transaction_start(handle->trans,
1157*25a68471Sdougm 				    handle->pg) != 0) {
11586185db85Sdougm 					ret = SA_SYSTEM_ERR;
11596185db85Sdougm 				}
11606185db85Sdougm 				if (ret != SA_OK) {
11616185db85Sdougm 					scf_transaction_destroy(handle->trans);
11626185db85Sdougm 					handle->trans = NULL;
11636185db85Sdougm 				}
11646185db85Sdougm 			} else {
11656185db85Sdougm 				ret = SA_SYSTEM_ERR;
11666185db85Sdougm 			}
11676185db85Sdougm 		}
11686185db85Sdougm 	}
11696185db85Sdougm 	if (ret == SA_SYSTEM_ERR &&
11706185db85Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
11716185db85Sdougm 		ret = SA_NO_PERMISSION;
11726185db85Sdougm 	}
11736185db85Sdougm 	return (ret);
11746185db85Sdougm }
11756185db85Sdougm 
11766185db85Sdougm /*
11776185db85Sdougm  * sa_end_transaction(handle)
11786185db85Sdougm  *
11796185db85Sdougm  * Commit the changes that were added to the transaction in the
11806185db85Sdougm  * handle. Do all necessary cleanup.
11816185db85Sdougm  */
11826185db85Sdougm 
11836185db85Sdougm int
11846185db85Sdougm sa_end_transaction(scfutilhandle_t *handle)
11856185db85Sdougm {
11866185db85Sdougm 	int ret = SA_OK;
11876185db85Sdougm 
11886185db85Sdougm 	if (handle->trans == NULL) {
11896185db85Sdougm 		ret = SA_SYSTEM_ERR;
11906185db85Sdougm 	} else {
11916185db85Sdougm 		if (scf_transaction_commit(handle->trans) < 0)
11926185db85Sdougm 			ret = SA_SYSTEM_ERR;
11936185db85Sdougm 		scf_transaction_destroy_children(handle->trans);
11946185db85Sdougm 		scf_transaction_destroy(handle->trans);
11956185db85Sdougm 		handle->trans = NULL;
11966185db85Sdougm 	}
11976185db85Sdougm 	return (ret);
11986185db85Sdougm }
11996185db85Sdougm 
12006185db85Sdougm /*
12016185db85Sdougm  * sa_abort_transaction(handle)
12026185db85Sdougm  *
12036185db85Sdougm  * Abort the changes that were added to the transaction in the
12046185db85Sdougm  * handle. Do all necessary cleanup.
12056185db85Sdougm  */
12066185db85Sdougm 
12076185db85Sdougm void
12086185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle)
12096185db85Sdougm {
12106185db85Sdougm 	if (handle->trans != NULL) {
12116185db85Sdougm 		scf_transaction_reset_all(handle->trans);
12126185db85Sdougm 		scf_transaction_destroy_children(handle->trans);
12136185db85Sdougm 		scf_transaction_destroy(handle->trans);
12146185db85Sdougm 		handle->trans = NULL;
12156185db85Sdougm 	}
12166185db85Sdougm }
12176185db85Sdougm 
12186185db85Sdougm /*
12196185db85Sdougm  * sa_set_property(handle, prop, value)
12206185db85Sdougm  *
1221*25a68471Sdougm  * Set a property transaction entry into the pending SMF transaction.
12226185db85Sdougm  */
12236185db85Sdougm 
12246185db85Sdougm int
12256185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
12266185db85Sdougm {
12276185db85Sdougm 	int ret = SA_OK;
12286185db85Sdougm 	scf_value_t *value;
12296185db85Sdougm 	scf_transaction_entry_t *entry;
12306185db85Sdougm 	/*
1231*25a68471Sdougm 	 * Properties must be set in transactions and don't take
12326185db85Sdougm 	 * effect until the transaction has been ended/committed.
12336185db85Sdougm 	 */
12346185db85Sdougm 	value = scf_value_create(handle->handle);
12356185db85Sdougm 	entry = scf_entry_create(handle->handle);
12366185db85Sdougm 	if (value != NULL && entry != NULL) {
12376185db85Sdougm 		if (scf_transaction_property_change(handle->trans, entry,
1238*25a68471Sdougm 		    propname, SCF_TYPE_ASTRING) == 0 ||
12396185db85Sdougm 		    scf_transaction_property_new(handle->trans, entry,
1240*25a68471Sdougm 		    propname, SCF_TYPE_ASTRING) == 0) {
12416185db85Sdougm 			if (scf_value_set_astring(value, valstr) == 0) {
12426185db85Sdougm 				if (scf_entry_add_value(entry, value) != 0) {
12436185db85Sdougm 					ret = SA_SYSTEM_ERR;
12446185db85Sdougm 					scf_value_destroy(value);
12456185db85Sdougm 				}
1246*25a68471Sdougm 				/* The value is in the transaction */
12476185db85Sdougm 				value = NULL;
12486185db85Sdougm 			} else {
1249*25a68471Sdougm 				/* Value couldn't be constructed */
12506185db85Sdougm 				ret = SA_SYSTEM_ERR;
12516185db85Sdougm 			}
1252*25a68471Sdougm 			/* The entry is in the transaction */
12536185db85Sdougm 			entry = NULL;
12546185db85Sdougm 		} else {
12556185db85Sdougm 			ret = SA_SYSTEM_ERR;
12566185db85Sdougm 		}
12576185db85Sdougm 	} else {
12586185db85Sdougm 		ret = SA_SYSTEM_ERR;
12596185db85Sdougm 	}
12606185db85Sdougm 	if (ret == SA_SYSTEM_ERR) {
12616185db85Sdougm 		switch (scf_error()) {
12626185db85Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
12636185db85Sdougm 			ret = SA_NO_PERMISSION;
12646185db85Sdougm 			break;
12656185db85Sdougm 		}
12666185db85Sdougm 	}
12676185db85Sdougm 	/*
1268*25a68471Sdougm 	 * Cleanup if there were any errors that didn't leave these
12696185db85Sdougm 	 * values where they would be cleaned up later.
12706185db85Sdougm 	 */
12716185db85Sdougm 	if (value != NULL)
12726185db85Sdougm 		scf_value_destroy(value);
12736185db85Sdougm 	if (entry != NULL)
12746185db85Sdougm 		scf_entry_destroy(entry);
12756185db85Sdougm 	return (ret);
12766185db85Sdougm }
12776185db85Sdougm 
12786185db85Sdougm /*
12796185db85Sdougm  * sa_commit_share(handle, group, share)
12806185db85Sdougm  *
1281*25a68471Sdougm  *	Commit this share to the repository.
12826185db85Sdougm  *	properties are added if they exist but can be added later.
12836185db85Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
12846185db85Sdougm  */
12856185db85Sdougm int
12866185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
12876185db85Sdougm {
12886185db85Sdougm 	int ret = SA_OK;
12896185db85Sdougm 	char *groupname;
12906185db85Sdougm 	char *name;
12916185db85Sdougm 	char *resource;
12926185db85Sdougm 	char *description;
12936185db85Sdougm 	char *sharename;
12946185db85Sdougm 	ssize_t proplen;
12956185db85Sdougm 	char *propstring;
12966185db85Sdougm 
12976185db85Sdougm 	/*
1298*25a68471Sdougm 	 * Don't commit in the zfs group. We do commit legacy
12996185db85Sdougm 	 * (default) and all other groups/shares. ZFS is handled
13006185db85Sdougm 	 * through the ZFS configuration rather than SMF.
13016185db85Sdougm 	 */
13026185db85Sdougm 
13036185db85Sdougm 	groupname = sa_get_group_attr(group, "name");
13046185db85Sdougm 	if (groupname != NULL) {
13056185db85Sdougm 		if (strcmp(groupname, "zfs") == 0) {
13066185db85Sdougm 			/*
1307*25a68471Sdougm 			 * Adding to the ZFS group will result in the sharenfs
13086185db85Sdougm 			 * property being set but we don't want to do anything
13096185db85Sdougm 			 * SMF related at this point.
13106185db85Sdougm 			 */
13116185db85Sdougm 			sa_free_attr_string(groupname);
13126185db85Sdougm 			return (ret);
13136185db85Sdougm 		}
13146185db85Sdougm 	}
13156185db85Sdougm 
13166185db85Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
13176185db85Sdougm 	propstring = malloc(proplen);
13186185db85Sdougm 	if (propstring == NULL)
13196185db85Sdougm 		ret = SA_NO_MEMORY;
13206185db85Sdougm 
13216185db85Sdougm 	if (groupname != NULL && ret == SA_OK) {
13226185db85Sdougm 		ret = sa_get_instance(handle, groupname);
13236185db85Sdougm 		sa_free_attr_string(groupname);
13246185db85Sdougm 		groupname = NULL;
13256185db85Sdougm 		sharename = sa_get_share_attr(share, "id");
13266185db85Sdougm 		if (sharename == NULL) {
13276185db85Sdougm 			/* slipped by */
13286185db85Sdougm 			char shname[SA_SHARE_UUID_BUFLEN];
13296185db85Sdougm 			generate_unique_sharename(shname);
13306185db85Sdougm 			xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
13316185db85Sdougm 			    (xmlChar *)shname);
13326185db85Sdougm 			sharename = strdup(shname);
13336185db85Sdougm 		}
13346185db85Sdougm 		if (sharename != NULL) {
1335f345c0beSdougm 			sigset_t old, new;
13366185db85Sdougm 			/*
1337*25a68471Sdougm 			 * Have a share name allocated so create a pgroup for
1338f345c0beSdougm 			 * it. It may already exist, but that is OK.  In order
1339f345c0beSdougm 			 * to avoid creating a share pgroup that doesn't have
1340f345c0beSdougm 			 * a path property, block signals around the critical
1341f345c0beSdougm 			 * region of creating the share pgroup and props.
13426185db85Sdougm 			 */
1343f345c0beSdougm 			(void) sigprocmask(SIG_BLOCK, NULL, &new);
1344f345c0beSdougm 			(void) sigaddset(&new, SIGHUP);
1345f345c0beSdougm 			(void) sigaddset(&new, SIGINT);
1346f345c0beSdougm 			(void) sigaddset(&new, SIGQUIT);
1347f345c0beSdougm 			(void) sigaddset(&new, SIGTSTP);
1348f345c0beSdougm 			(void) sigprocmask(SIG_SETMASK, &new, &old);
1349f345c0beSdougm 
13506185db85Sdougm 			ret = sa_create_pgroup(handle, sharename);
13516185db85Sdougm 			if (ret == SA_OK) {
13526185db85Sdougm 				/*
1353*25a68471Sdougm 				 * Now start the transaction for the
13546185db85Sdougm 				 * properties that define this share. They may
13556185db85Sdougm 				 * exist so attempt to update before create.
13566185db85Sdougm 				 */
13576185db85Sdougm 				ret = sa_start_transaction(handle, sharename);
13586185db85Sdougm 			}
13596185db85Sdougm 			if (ret == SA_OK) {
13606185db85Sdougm 				name = sa_get_share_attr(share, "path");
13616185db85Sdougm 				if (name != NULL) {
1362*25a68471Sdougm 					/*
1363*25a68471Sdougm 					 * There needs to be a path
1364*25a68471Sdougm 					 * for a share to exist.
1365*25a68471Sdougm 					 */
1366*25a68471Sdougm 					ret = sa_set_property(handle, "path",
1367*25a68471Sdougm 					    name);
13686185db85Sdougm 					sa_free_attr_string(name);
13696185db85Sdougm 				} else {
13706185db85Sdougm 					ret = SA_NO_MEMORY;
13716185db85Sdougm 				}
13726185db85Sdougm 			}
13736185db85Sdougm 			if (ret == SA_OK) {
1374*25a68471Sdougm 				resource = sa_get_share_attr(share,
1375*25a68471Sdougm 				    "resource");
13766185db85Sdougm 				if (resource != NULL) {
1377*25a68471Sdougm 					ret = sa_set_property(handle,
1378*25a68471Sdougm 					    "resource", resource);
13796185db85Sdougm 					sa_free_attr_string(resource);
13806185db85Sdougm 				}
13816185db85Sdougm 			}
13826185db85Sdougm 			if (ret == SA_OK) {
13836185db85Sdougm 				description = sa_get_share_description(share);
13846185db85Sdougm 				if (description != NULL) {
1385*25a68471Sdougm 					ret = sa_set_property(handle,
1386*25a68471Sdougm 					    "description",
13876185db85Sdougm 					    description);
13886185db85Sdougm 					sa_free_share_description(description);
13896185db85Sdougm 				}
13906185db85Sdougm 			}
1391*25a68471Sdougm 			/* Make sure we cleanup the transaction */
13926185db85Sdougm 			if (ret == SA_OK) {
13936185db85Sdougm 				ret = sa_end_transaction(handle);
13946185db85Sdougm 			} else {
13956185db85Sdougm 				sa_abort_transaction(handle);
13966185db85Sdougm 			}
1397f345c0beSdougm 
1398f345c0beSdougm 			(void) sigprocmask(SIG_SETMASK, &old, NULL);
1399f345c0beSdougm 
14006185db85Sdougm 			free(sharename);
14016185db85Sdougm 		}
14026185db85Sdougm 	}
14036185db85Sdougm 	if (ret == SA_SYSTEM_ERR) {
14046185db85Sdougm 		int err = scf_error();
14056185db85Sdougm 		if (err == SCF_ERROR_PERMISSION_DENIED)
14066185db85Sdougm 			ret = SA_NO_PERMISSION;
14076185db85Sdougm 	}
14086185db85Sdougm 	if (propstring != NULL)
14096185db85Sdougm 		free(propstring);
14106185db85Sdougm 	if (groupname != NULL)
14116185db85Sdougm 		sa_free_attr_string(groupname);
14126185db85Sdougm 
14136185db85Sdougm 	return (ret);
14146185db85Sdougm }
14156185db85Sdougm 
14166185db85Sdougm /*
14176185db85Sdougm  * sa_delete_share(handle, group, share)
14186185db85Sdougm  *
1419*25a68471Sdougm  * Remove the specified share from the group (and service instance).
14206185db85Sdougm  */
14216185db85Sdougm 
14226185db85Sdougm int
14236185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
14246185db85Sdougm {
14256185db85Sdougm 	int ret = SA_OK;
14266185db85Sdougm 	char *groupname = NULL;
14276185db85Sdougm 	char *shareid = NULL;
14286185db85Sdougm 	sa_optionset_t opt;
14296185db85Sdougm 	sa_security_t sec;
14306185db85Sdougm 	ssize_t proplen;
14316185db85Sdougm 	char *propstring;
14326185db85Sdougm 
14336185db85Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
14346185db85Sdougm 	propstring = malloc(proplen);
14356185db85Sdougm 	if (propstring == NULL)
14366185db85Sdougm 		ret = SA_NO_MEMORY;
14376185db85Sdougm 
14386185db85Sdougm 	if (ret == SA_OK) {
14396185db85Sdougm 		groupname = sa_get_group_attr(group, "name");
14406185db85Sdougm 		shareid = sa_get_share_attr(share, "id");
1441*25a68471Sdougm 		if (groupname == NULL || shareid == NULL) {
1442*25a68471Sdougm 			ret = SA_CONFIG_ERR;
1443*25a68471Sdougm 			goto out;
1444*25a68471Sdougm 		}
14456185db85Sdougm 		ret = sa_get_instance(handle, groupname);
14466185db85Sdougm 		if (ret == SA_OK) {
1447*25a68471Sdougm 			/* If a share has properties, remove them */
14486185db85Sdougm 			ret = sa_delete_pgroup(handle, shareid);
1449*25a68471Sdougm 			for (opt = sa_get_optionset(share, NULL);
1450*25a68471Sdougm 			    opt != NULL;
14516185db85Sdougm 			    opt = sa_get_next_optionset(opt)) {
14526185db85Sdougm 				char *proto;
14536185db85Sdougm 				proto = sa_get_optionset_attr(opt, "type");
14546185db85Sdougm 				if (proto != NULL) {
1455*25a68471Sdougm 					(void) snprintf(propstring,
1456*25a68471Sdougm 					    proplen, "%s_%s", shareid,
1457*25a68471Sdougm 					    proto);
1458*25a68471Sdougm 					ret = sa_delete_pgroup(handle,
1459*25a68471Sdougm 					    propstring);
14606185db85Sdougm 					sa_free_attr_string(proto);
14616185db85Sdougm 				} else {
14626185db85Sdougm 					ret = SA_NO_MEMORY;
14636185db85Sdougm 				}
14646185db85Sdougm 			}
14656185db85Sdougm 			/*
1466*25a68471Sdougm 			 * If a share has security/negotiable
14676185db85Sdougm 			 * properties, remove them.
14686185db85Sdougm 			 */
1469*25a68471Sdougm 			for (sec = sa_get_security(share, NULL, NULL);
1470*25a68471Sdougm 			    sec != NULL;
14716185db85Sdougm 			    sec = sa_get_next_security(sec)) {
14726185db85Sdougm 				char *proto;
14736185db85Sdougm 				char *sectype;
14746185db85Sdougm 				proto = sa_get_security_attr(sec, "type");
14756185db85Sdougm 				sectype = sa_get_security_attr(sec, "sectype");
14766185db85Sdougm 				if (proto != NULL && sectype != NULL) {
1477*25a68471Sdougm 					(void) snprintf(propstring, proplen,
1478*25a68471Sdougm 					    "%s_%s_%s", shareid,  proto,
1479*25a68471Sdougm 					    sectype);
1480*25a68471Sdougm 					ret = sa_delete_pgroup(handle,
1481*25a68471Sdougm 					    propstring);
14826185db85Sdougm 				} else {
14836185db85Sdougm 					ret = SA_NO_MEMORY;
14846185db85Sdougm 				}
14856185db85Sdougm 				if (proto != NULL)
14866185db85Sdougm 					sa_free_attr_string(proto);
14876185db85Sdougm 				if (sectype != NULL)
14886185db85Sdougm 					sa_free_attr_string(sectype);
14896185db85Sdougm 			}
14906185db85Sdougm 		}
14916185db85Sdougm 	}
1492*25a68471Sdougm out:
14936185db85Sdougm 	if (groupname != NULL)
14946185db85Sdougm 		sa_free_attr_string(groupname);
14956185db85Sdougm 	if (shareid != NULL)
14966185db85Sdougm 		sa_free_attr_string(shareid);
14976185db85Sdougm 	if (propstring != NULL)
14986185db85Sdougm 		free(propstring);
14996185db85Sdougm 
15006185db85Sdougm 	return (ret);
15016185db85Sdougm }
1502