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>
38*5331Samw #include <ctype.h>
393034Sdougm #include <errno.h>
403034Sdougm #include <uuid/uuid.h>
413034Sdougm #include <sys/param.h>
423348Sdougm #include <signal.h>
433034Sdougm 
443034Sdougm ssize_t scf_max_name_len;
453034Sdougm extern struct sa_proto_plugin *sap_proto_list;
463910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
473034Sdougm 
483034Sdougm /*
493034Sdougm  * The SMF facility uses some properties that must exist. We want to
503034Sdougm  * skip over these when processing protocol options.
513034Sdougm  */
523034Sdougm static char *skip_props[] = {
533034Sdougm 	"modify_authorization",
543034Sdougm 	"action_authorization",
553034Sdougm 	"value_authorization",
563034Sdougm 	NULL
573034Sdougm };
583034Sdougm 
593034Sdougm /*
603034Sdougm  * sa_scf_fini(handle)
613034Sdougm  *
624653Sdougm  * Must be called when done. Called with the handle allocated in
633034Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
643034Sdougm  * still in use. Called by sa_fini().
653034Sdougm  */
663034Sdougm 
673034Sdougm void
683034Sdougm sa_scf_fini(scfutilhandle_t *handle)
693034Sdougm {
703034Sdougm 	if (handle != NULL) {
714653Sdougm 		int unbind = 0;
724653Sdougm 		if (handle->scope != NULL) {
734653Sdougm 			unbind = 1;
744653Sdougm 			scf_scope_destroy(handle->scope);
754653Sdougm 		}
764653Sdougm 		if (handle->instance != NULL)
774653Sdougm 			scf_instance_destroy(handle->instance);
784653Sdougm 		if (handle->service != NULL)
794653Sdougm 			scf_service_destroy(handle->service);
804653Sdougm 		if (handle->pg != NULL)
814653Sdougm 			scf_pg_destroy(handle->pg);
824653Sdougm 		if (handle->handle != NULL) {
834653Sdougm 			handle->scf_state = SCH_STATE_UNINIT;
844653Sdougm 			if (unbind)
854653Sdougm 				(void) scf_handle_unbind(handle->handle);
864653Sdougm 			scf_handle_destroy(handle->handle);
874653Sdougm 		}
884653Sdougm 		free(handle);
893034Sdougm 	}
903034Sdougm }
913034Sdougm 
923034Sdougm /*
933034Sdougm  * sa_scf_init()
943034Sdougm  *
954653Sdougm  * Must be called before using any of the SCF functions. Called by
963034Sdougm  * sa_init() during the API setup.
973034Sdougm  */
983034Sdougm 
993034Sdougm scfutilhandle_t *
1003910Sdougm sa_scf_init(sa_handle_impl_t ihandle)
1013034Sdougm {
1023034Sdougm 	scfutilhandle_t *handle;
1033034Sdougm 
1043034Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1053034Sdougm 	if (scf_max_name_len <= 0)
1064653Sdougm 		scf_max_name_len = SA_MAX_NAME_LEN + 1;
1073034Sdougm 
1083034Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
1094653Sdougm 	if (handle == NULL)
1104653Sdougm 		return (handle);
1114345Sdougm 
1124653Sdougm 	ihandle->scfhandle = handle;
1134653Sdougm 	handle->scf_state = SCH_STATE_INITIALIZING;
1144653Sdougm 	handle->handle = scf_handle_create(SCF_VERSION);
1154653Sdougm 	if (handle->handle == NULL) {
1163034Sdougm 		free(handle);
1173034Sdougm 		handle = NULL;
1183034Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
1194653Sdougm 		    scf_strerror(scf_error()));
1204653Sdougm 		return (handle);
1213034Sdougm 	}
1224653Sdougm 	if (scf_handle_bind(handle->handle) != 0)
1234653Sdougm 		goto err;
1244653Sdougm 
1254653Sdougm 	handle->scope = scf_scope_create(handle->handle);
1264653Sdougm 	handle->service = scf_service_create(handle->handle);
1274653Sdougm 	handle->pg = scf_pg_create(handle->handle);
1284653Sdougm 
1294653Sdougm 	/* Make sure we have sufficient SMF running */
1304653Sdougm 	handle->instance = scf_instance_create(handle->handle);
1314653Sdougm 	if (handle->scope == NULL || handle->service == NULL ||
1324653Sdougm 	    handle->pg == NULL || handle->instance == NULL)
1334653Sdougm 		goto err;
1344653Sdougm 	if (scf_handle_get_scope(handle->handle,
1354653Sdougm 	    SCF_SCOPE_LOCAL, handle->scope) != 0)
1364653Sdougm 		goto err;
1374653Sdougm 	if (scf_scope_get_service(handle->scope,
1384653Sdougm 	    SA_GROUP_SVC_NAME, handle->service) != 0)
1394653Sdougm 		goto err;
1404653Sdougm 
1414653Sdougm 	handle->scf_state = SCH_STATE_INIT;
1424653Sdougm 	if (sa_get_instance(handle, "default") != SA_OK) {
1434653Sdougm 		char **protolist;
1444653Sdougm 		int numprotos, i;
1454653Sdougm 		sa_group_t defgrp;
1464653Sdougm 		defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
1474653Sdougm 		if (defgrp != NULL) {
1484653Sdougm 			numprotos = sa_get_protocols(
1494653Sdougm 			    &protolist);
1504653Sdougm 			for (i = 0; i < numprotos; i++)
1514653Sdougm 				(void) sa_create_optionset(defgrp,
1524653Sdougm 				    protolist[i]);
1534653Sdougm 			if (protolist != NULL)
1544653Sdougm 				free(protolist);
1554653Sdougm 		}
1564653Sdougm 	}
1574653Sdougm 
1583034Sdougm 	return (handle);
1593034Sdougm 
1604653Sdougm 	/* Error handling/unwinding */
1613034Sdougm err:
1623034Sdougm 	(void) sa_scf_fini(handle);
1633034Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
1644653Sdougm 	    scf_strerror(scf_error()));
1653034Sdougm 	return (NULL);
1663034Sdougm }
1673034Sdougm 
1683034Sdougm /*
1693034Sdougm  * get_scf_limit(name)
1703034Sdougm  *
1713034Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
1723034Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
1733034Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
1743034Sdougm  * (1024) so we have a reasonable default buffer size.
1753034Sdougm  */
1763034Sdougm static ssize_t
1773034Sdougm get_scf_limit(uint32_t name)
1783034Sdougm {
1793034Sdougm 	ssize_t vallen;
1803034Sdougm 
1813034Sdougm 	vallen = scf_limit(name);
1823034Sdougm 	if (vallen == (ssize_t)-1)
1834653Sdougm 		vallen = MAXPATHLEN;
1843034Sdougm 	return (vallen);
1853034Sdougm }
1863034Sdougm 
1873034Sdougm /*
1883034Sdougm  * skip_property(name)
1893034Sdougm  *
1904653Sdougm  * Internal function to check to see if a property is an SMF magic
1913034Sdougm  * property that needs to be skipped.
1923034Sdougm  */
1933034Sdougm static int
1943034Sdougm skip_property(char *name)
1953034Sdougm {
1963034Sdougm 	int i;
1973034Sdougm 
1983034Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
1994653Sdougm 		if (strcmp(name, skip_props[i]) == 0)
2003034Sdougm 		return (1);
2013034Sdougm 	return (0);
2023034Sdougm }
2033034Sdougm 
2043034Sdougm /*
2053034Sdougm  * generate_unique_sharename(sharename)
2063034Sdougm  *
2073034Sdougm  * Shares are represented in SMF as property groups. Due to share
2083034Sdougm  * paths containing characters that are not allowed in SMF names and
2093034Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
2103034Sdougm  */
2113034Sdougm 
2123034Sdougm static void
2133034Sdougm generate_unique_sharename(char *sharename)
2143034Sdougm {
2153034Sdougm 	uuid_t uuid;
2163034Sdougm 
2173034Sdougm 	uuid_generate(uuid);
2183034Sdougm 	(void) strcpy(sharename, "S-");
2193034Sdougm 	uuid_unparse(uuid, sharename + 2);
2203034Sdougm }
2213034Sdougm 
2223034Sdougm /*
2233034Sdougm  * valid_protocol(proto)
2243034Sdougm  *
2254653Sdougm  * Check to see if the specified protocol is a valid one for the
2263034Sdougm  * general sharemgr facility. We determine this by checking which
2273034Sdougm  * plugin protocols were found.
2283034Sdougm  */
2293034Sdougm 
2303034Sdougm static int
2313034Sdougm valid_protocol(char *proto)
2323034Sdougm {
2333034Sdougm 	struct sa_proto_plugin *plugin;
2343034Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
2353034Sdougm 	    plugin = plugin->plugin_next)
2364653Sdougm 		if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
2374653Sdougm 			return (1);
2383034Sdougm 	return (0);
2393034Sdougm }
2403034Sdougm 
2413034Sdougm /*
2423034Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2433034Sdougm  *
2444653Sdougm  * Extract the name property group and create the specified type of
2453034Sdougm  * node on the provided group.  type will be optionset or security.
2463034Sdougm  */
2473034Sdougm 
2483034Sdougm static int
2493034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2503034Sdougm 			scf_propertygroup_t *pg,
2513034Sdougm 			char *nodetype, char *proto, char *sectype)
2523034Sdougm {
2533034Sdougm 	xmlNodePtr node;
2543034Sdougm 	scf_iter_t *iter;
2553034Sdougm 	scf_property_t *prop;
2563034Sdougm 	scf_value_t *value;
2573034Sdougm 	char *name;
2583034Sdougm 	char *valuestr;
2593034Sdougm 	ssize_t vallen;
2603034Sdougm 	int ret = SA_OK;
2613034Sdougm 
2623034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2633034Sdougm 
2643034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
2654653Sdougm 	if (node == NULL)
2664653Sdougm 		return (ret);
2674653Sdougm 
2684653Sdougm 	if (proto != NULL)
2693034Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2704653Sdougm 	if (sectype != NULL)
2713034Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
2724653Sdougm 	/*
2734653Sdougm 	 * Have node to work with so iterate over the properties
2744653Sdougm 	 * in the pg and create option sub nodes.
2754653Sdougm 	 */
2764653Sdougm 	iter = scf_iter_create(handle->handle);
2774653Sdougm 	value = scf_value_create(handle->handle);
2784653Sdougm 	prop = scf_property_create(handle->handle);
2794653Sdougm 	name = malloc(scf_max_name_len);
2804653Sdougm 	valuestr = malloc(vallen);
2814653Sdougm 	/*
2824653Sdougm 	 * Want to iterate through the properties and add them
2834653Sdougm 	 * to the base optionset.
2844653Sdougm 	 */
2854653Sdougm 	if (iter == NULL || value == NULL || prop == NULL ||
2864653Sdougm 	    valuestr == NULL || name == NULL) {
2874653Sdougm 		ret = SA_NO_MEMORY;
2884653Sdougm 		goto out;
2894653Sdougm 	}
2904653Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
2914653Sdougm 		/* Now iterate the properties in the group */
2924653Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
2934653Sdougm 			/* have a property */
2944653Sdougm 			if (scf_property_get_name(prop, name,
2954653Sdougm 			    scf_max_name_len) > 0) {
2964653Sdougm 				sa_property_t saprop;
2974653Sdougm 				/* Some properties are part of the framework */
2983034Sdougm 				if (skip_property(name))
2994653Sdougm 					continue;
3004653Sdougm 				if (scf_property_get_value(prop, value) != 0)
3014653Sdougm 					continue;
3024653Sdougm 				if (scf_value_get_astring(value, valuestr,
3034653Sdougm 				    vallen) < 0)
3044653Sdougm 					continue;
3054653Sdougm 				saprop = sa_create_property(name, valuestr);
3064653Sdougm 				if (saprop != NULL) {
3073034Sdougm 					/*
3084653Sdougm 					 * Since in SMF, don't
3093034Sdougm 					 * recurse. Use xmlAddChild
3103034Sdougm 					 * directly, instead.
3113034Sdougm 					 */
3124653Sdougm 					xmlAddChild(node,
3134653Sdougm 					    (xmlNodePtr) saprop);
3143034Sdougm 				}
3153034Sdougm 			}
3163034Sdougm 		}
3173034Sdougm 	}
3184653Sdougm out:
3194653Sdougm 	/* cleanup to avoid memory leaks */
3204653Sdougm 	if (value != NULL)
3214653Sdougm 		scf_value_destroy(value);
3224653Sdougm 	if (iter != NULL)
3234653Sdougm 		scf_iter_destroy(iter);
3244653Sdougm 	if (prop != NULL)
3254653Sdougm 		scf_property_destroy(prop);
3264653Sdougm 	if (name != NULL)
3274653Sdougm 		free(name);
3284653Sdougm 	if (valuestr != NULL)
3294653Sdougm 		free(valuestr);
3304653Sdougm 
3313034Sdougm 	return (ret);
3323034Sdougm }
3333034Sdougm 
3343034Sdougm /*
3353034Sdougm  * sa_extract_attrs(root, handle, instance)
3363034Sdougm  *
3374653Sdougm  * Local function to extract the actual attributes/properties from the
3383034Sdougm  * property group of the service instance. These are the well known
3393034Sdougm  * attributes of "state" and "zfs". If additional attributes are
3403034Sdougm  * added, they should be added here.
3413034Sdougm  */
3423034Sdougm 
3433034Sdougm static void
3443034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3453034Sdougm 		    scf_instance_t *instance)
3463034Sdougm {
3473034Sdougm 	scf_property_t *prop;
3483034Sdougm 	scf_value_t *value;
3493034Sdougm 	char *valuestr;
3503034Sdougm 	ssize_t vallen;
3513034Sdougm 
3523034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3533034Sdougm 	prop = scf_property_create(handle->handle);
3543034Sdougm 	value = scf_value_create(handle->handle);
3553034Sdougm 	valuestr = malloc(vallen);
3564653Sdougm 	if (prop == NULL || value == NULL || valuestr == NULL ||
3574653Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
3584653Sdougm 		goto out;
3594653Sdougm 	}
3604653Sdougm 	/*
3614653Sdougm 	 * Have a property group with desired name so now get
3624653Sdougm 	 * the known attributes.
3634653Sdougm 	 */
3644653Sdougm 	if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
3654653Sdougm 		/* Found the property so get the value */
3663034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
3674653Sdougm 			if (scf_value_get_astring(value, valuestr,
3684653Sdougm 			    vallen) >= 0) {
3694653Sdougm 				xmlSetProp(root, (xmlChar *)"state",
3703034Sdougm 				    (xmlChar *)valuestr);
3714653Sdougm 			}
3723034Sdougm 		}
3734653Sdougm 	}
3744653Sdougm 	if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
3754653Sdougm 		/* Found the property so get the value */
3763034Sdougm 		if (scf_property_get_value(prop, value) == 0) {
3774653Sdougm 			if (scf_value_get_astring(value, valuestr,
3784653Sdougm 			    vallen) > 0) {
3794653Sdougm 				xmlSetProp(root, (xmlChar *)"zfs",
3803034Sdougm 				    (xmlChar *)valuestr);
3814653Sdougm 			}
3823034Sdougm 		}
3833034Sdougm 	}
3844653Sdougm out:
3853034Sdougm 	if (valuestr != NULL)
3864653Sdougm 		free(valuestr);
3873034Sdougm 	if (value != NULL)
3884653Sdougm 		scf_value_destroy(value);
3893034Sdougm 	if (prop != NULL)
3904653Sdougm 		scf_property_destroy(prop);
3913034Sdougm }
3923034Sdougm 
3933034Sdougm /*
3944653Sdougm  * List of known share attributes.
3953034Sdougm  */
3963034Sdougm 
3973034Sdougm static char *share_attr[] = {
3983034Sdougm 	"path",
3993034Sdougm 	"id",
400*5331Samw 	"drive-letter",
401*5331Samw 	"exclude",
4023034Sdougm 	NULL,
4033034Sdougm };
4043034Sdougm 
4053034Sdougm static int
4063034Sdougm is_share_attr(char *name)
4073034Sdougm {
4083034Sdougm 	int i;
4093034Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
4104653Sdougm 		if (strcmp(name, share_attr[i]) == 0)
4114653Sdougm 			return (1);
4123034Sdougm 	return (0);
4133034Sdougm }
4143034Sdougm 
4153034Sdougm /*
416*5331Samw  * _sa_make_resource(node, valuestr)
417*5331Samw  *
418*5331Samw  * Make a resource node on the share node. The valusestr will either
419*5331Samw  * be old format (SMF acceptable string) or new format (pretty much an
420*5331Samw  * arbitrary string with "nnn:" prefixing in order to persist
421*5331Samw  * mapping). The input valuestr will get modified in place. This is
422*5331Samw  * only used in SMF repository parsing. A possible third field will be
423*5331Samw  * a "description" string.
424*5331Samw  */
425*5331Samw 
426*5331Samw static void
427*5331Samw _sa_make_resource(xmlNodePtr node, char *valuestr)
428*5331Samw {
429*5331Samw 	char *idx;
430*5331Samw 	char *name;
431*5331Samw 	char *description = NULL;
432*5331Samw 
433*5331Samw 	idx = valuestr;
434*5331Samw 	name = strchr(valuestr, ':');
435*5331Samw 	if (name == NULL) {
436*5331Samw 		/* this is old form so give an index of "0" */
437*5331Samw 		idx = "0";
438*5331Samw 		name = valuestr;
439*5331Samw 	} else {
440*5331Samw 		/* NUL the ':' and move past it */
441*5331Samw 		*name++ = '\0';
442*5331Samw 		/* There could also be a description string */
443*5331Samw 		description = strchr(name, ':');
444*5331Samw 		if (description != NULL)
445*5331Samw 			*description++ = '\0';
446*5331Samw 	}
447*5331Samw 	node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
448*5331Samw 	if (node != NULL) {
449*5331Samw 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
450*5331Samw 		xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
451*5331Samw 		/* SMF values are always persistent */
452*5331Samw 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
453*5331Samw 		if (description != NULL && strlen(description) > 0) {
454*5331Samw 			(void) xmlNewChild(node, NULL, (xmlChar *)"description",
455*5331Samw 			    (xmlChar *)description);
456*5331Samw 		}
457*5331Samw 	}
458*5331Samw }
459*5331Samw 
460*5331Samw 
461*5331Samw /*
4623034Sdougm  * sa_share_from_pgroup
4633034Sdougm  *
4644653Sdougm  * Extract the share definition from the share property group. We do
4653034Sdougm  * some sanity checking to avoid bad data.
4663034Sdougm  *
4673034Sdougm  * Since this is only constructing the internal data structures, we
4683034Sdougm  * don't use the sa_* functions most of the time.
4693034Sdougm  */
4703034Sdougm void
4713034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4723034Sdougm 			scf_propertygroup_t *pg, char *id)
4733034Sdougm {
4743034Sdougm 	xmlNodePtr node;
4753034Sdougm 	char *name;
4763034Sdougm 	scf_iter_t *iter;
4773034Sdougm 	scf_property_t *prop;
4783034Sdougm 	scf_value_t *value;
4793034Sdougm 	ssize_t vallen;
4803034Sdougm 	char *valuestr;
4813034Sdougm 	int ret = SA_OK;
4823348Sdougm 	int have_path = 0;
4833034Sdougm 
4843034Sdougm 	/*
4853034Sdougm 	 * While preliminary check (starts with 'S') passed before
4863034Sdougm 	 * getting here. Need to make sure it is in ID syntax
4873034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
4883034Sdougm 	 * pgroups.
4893034Sdougm 	 */
4903034Sdougm 	vallen = strlen(id);
4913034Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
4924653Sdougm 		uuid_t uuid;
4934653Sdougm 		if (strncmp(id, SA_SHARE_PG_PREFIX,
4944653Sdougm 		    SA_SHARE_PG_PREFIXLEN) != 0 ||
4954653Sdougm 		    uuid_parse(id + 2, uuid) < 0)
4964653Sdougm 			return;
4974653Sdougm 	} else {
4983034Sdougm 		return;
4993034Sdougm 	}
5003034Sdougm 
5013034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
5023034Sdougm 
5033034Sdougm 	iter = scf_iter_create(handle->handle);
5043034Sdougm 	value = scf_value_create(handle->handle);
5053034Sdougm 	prop = scf_property_create(handle->handle);
5063034Sdougm 	name = malloc(scf_max_name_len);
5073034Sdougm 	valuestr = malloc(vallen);
5083034Sdougm 
5093034Sdougm 	/*
5104653Sdougm 	 * Construct the share XML node. It is similar to sa_add_share
5113034Sdougm 	 * but never changes the repository. Also, there won't be any
5123034Sdougm 	 * ZFS or transient shares.  Root will be the group it is
5133034Sdougm 	 * associated with.
5143034Sdougm 	 */
5153034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
5163034Sdougm 	if (node != NULL) {
5173034Sdougm 		/*
5184653Sdougm 		 * Make sure the UUID part of the property group is
5193034Sdougm 		 * stored in the share "id" property. We use this
5203034Sdougm 		 * later.
5213034Sdougm 		 */
5224653Sdougm 		xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
5234653Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
5243034Sdougm 	}
5253034Sdougm 
5264653Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
5274653Sdougm 		goto out;
5284653Sdougm 
5294653Sdougm 	/* Iterate over the share pg properties */
5304653Sdougm 	if (scf_iter_pg_properties(iter, pg) != 0)
5314653Sdougm 		goto out;
5324653Sdougm 
5334653Sdougm 	while (scf_iter_next_property(iter, prop) > 0) {
5344653Sdougm 		ret = SA_SYSTEM_ERR; /* assume the worst */
5354653Sdougm 		if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
5363034Sdougm 			if (scf_property_get_value(prop, value) == 0) {
5374653Sdougm 				if (scf_value_get_astring(value, valuestr,
5384653Sdougm 				    vallen) >= 0) {
5394653Sdougm 					ret = SA_OK;
5404653Sdougm 				}
541*5331Samw 			} else if (strcmp(name, "resource") == 0) {
542*5331Samw 				ret = SA_OK;
5433034Sdougm 			}
5444653Sdougm 		}
545*5331Samw 		if (ret != SA_OK)
546*5331Samw 			continue;
547*5331Samw 		/*
548*5331Samw 		 * Check that we have the "path" property in
549*5331Samw 		 * name. The string in name will always be nul
550*5331Samw 		 * terminated if scf_property_get_name()
551*5331Samw 		 * succeeded.
552*5331Samw 		 */
553*5331Samw 		if (strcmp(name, "path") == 0)
554*5331Samw 			have_path = 1;
555*5331Samw 		if (is_share_attr(name)) {
5563348Sdougm 			/*
557*5331Samw 			 * If a share attr, then simple -
558*5331Samw 			 * usually path and id name
5593348Sdougm 			 */
560*5331Samw 			xmlSetProp(node, (xmlChar *)name,
561*5331Samw 			    (xmlChar *)valuestr);
562*5331Samw 		} else if (strcmp(name, "resource") == 0) {
563*5331Samw 			/*
564*5331Samw 			 * Resource names handled differently since
565*5331Samw 			 * there can be multiple on each share. The
566*5331Samw 			 * "resource" id must be preserved since this
567*5331Samw 			 * will be used by some protocols in mapping
568*5331Samw 			 * "property spaces" to names and is always
569*5331Samw 			 * used to create SMF property groups specific
570*5331Samw 			 * to resources.  CIFS needs this.  The first
571*5331Samw 			 * value is present so add and then loop for
572*5331Samw 			 * any additional. Since this is new and
573*5331Samw 			 * previous values may exist, handle
574*5331Samw 			 * conversions.
575*5331Samw 			 */
576*5331Samw 			scf_iter_t *viter;
577*5331Samw 			viter = scf_iter_create(handle->handle);
578*5331Samw 			if (viter != NULL &&
579*5331Samw 			    scf_iter_property_values(viter, prop) == 0) {
580*5331Samw 				while (scf_iter_next_value(viter, value) > 0) {
581*5331Samw 					/* Have a value so process it */
582*5331Samw 					if (scf_value_get_ustring(value,
583*5331Samw 					    valuestr, vallen) >= 0) {
584*5331Samw 						/* have a ustring */
585*5331Samw 						_sa_make_resource(node,
586*5331Samw 						    valuestr);
587*5331Samw 					} else if (scf_value_get_astring(value,
588*5331Samw 					    valuestr, vallen) >= 0) {
589*5331Samw 						/* have an astring */
590*5331Samw 						_sa_make_resource(node,
591*5331Samw 						    valuestr);
592*5331Samw 					}
5934653Sdougm 				}
594*5331Samw 				scf_iter_destroy(viter);
595*5331Samw 			}
596*5331Samw 		} else {
597*5331Samw 			if (strcmp(name, "description") == 0) {
598*5331Samw 				/* We have a description node */
599*5331Samw 				xmlNodePtr desc;
600*5331Samw 				desc = xmlNewChild(node, NULL,
601*5331Samw 				    (xmlChar *)"description", NULL);
602*5331Samw 				if (desc != NULL)
603*5331Samw 					xmlNodeSetContent(desc,
604*5331Samw 					    (xmlChar *)valuestr);
6053034Sdougm 			}
6063034Sdougm 		}
6073034Sdougm 	}
6084653Sdougm out:
6093348Sdougm 	/*
6104653Sdougm 	 * A share without a path is broken so we want to not include
6113348Sdougm 	 * these.  They shouldn't happen but if you kill a sharemgr in
6123348Sdougm 	 * the process of creating a share, it could happen.  They
6133348Sdougm 	 * should be harmless.  It is also possible that another
6143348Sdougm 	 * sharemgr is running and in the process of creating a share.
6153348Sdougm 	 */
6163348Sdougm 	if (have_path == 0 && node != NULL) {
6174653Sdougm 		xmlUnlinkNode(node);
6184653Sdougm 		xmlFreeNode(node);
6193348Sdougm 	}
6203034Sdougm 	if (name != NULL)
6214653Sdougm 		free(name);
6223034Sdougm 	if (valuestr != NULL)
6234653Sdougm 		free(valuestr);
6243034Sdougm 	if (value != NULL)
6254653Sdougm 		scf_value_destroy(value);
6263034Sdougm 	if (iter != NULL)
6274653Sdougm 		scf_iter_destroy(iter);
6283034Sdougm 	if (prop != NULL)
6294653Sdougm 		scf_property_destroy(prop);
6303034Sdougm }
6313034Sdougm 
6323034Sdougm /*
6333034Sdougm  * find_share_by_id(shareid)
6343034Sdougm  *
6353034Sdougm  * Search all shares in all groups until we find the share represented
6363034Sdougm  * by "id".
6373034Sdougm  */
6383034Sdougm 
6393034Sdougm static sa_share_t
6403910Sdougm find_share_by_id(sa_handle_t handle, char *shareid)
6413034Sdougm {
6423034Sdougm 	sa_group_t group;
6433034Sdougm 	sa_share_t share = NULL;
6443034Sdougm 	char *id = NULL;
6453034Sdougm 	int done = 0;
6463034Sdougm 
6474653Sdougm 	for (group = sa_get_group(handle, NULL);
6484653Sdougm 	    group != NULL && !done;
6494653Sdougm 	    group = sa_get_next_group(group)) {
6504653Sdougm 		for (share = sa_get_share(group, NULL);
6514653Sdougm 		    share != NULL;
6524653Sdougm 		    share = sa_get_next_share(share)) {
6533034Sdougm 			id = sa_get_share_attr(share, "id");
6543034Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
6553034Sdougm 				sa_free_attr_string(id);
6563034Sdougm 				id = NULL;
6573034Sdougm 				done++;
6583034Sdougm 				break;
6593034Sdougm 			}
6603034Sdougm 			if (id != NULL) {
6614653Sdougm 				sa_free_attr_string(id);
6624653Sdougm 				id = NULL;
6633034Sdougm 			}
6643034Sdougm 		}
6653034Sdougm 	}
6663034Sdougm 	return (share);
6673034Sdougm }
6683034Sdougm 
6693034Sdougm /*
670*5331Samw  * find_resource_by_index(share, index)
671*5331Samw  *
672*5331Samw  * Search the resource records on the share for the id index.
673*5331Samw  */
674*5331Samw static sa_resource_t
675*5331Samw find_resource_by_index(sa_share_t share, char *index)
676*5331Samw {
677*5331Samw 	sa_resource_t resource;
678*5331Samw 	sa_resource_t found = NULL;
679*5331Samw 	char *id;
680*5331Samw 
681*5331Samw 	for (resource = sa_get_share_resource(share, NULL);
682*5331Samw 	    resource != NULL && found == NULL;
683*5331Samw 	    resource = sa_get_next_resource(resource)) {
684*5331Samw 		id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
685*5331Samw 		if (id != NULL) {
686*5331Samw 			if (strcmp(id, index) == 0) {
687*5331Samw 				/* found it so save in "found" */
688*5331Samw 				found = resource;
689*5331Samw 			}
690*5331Samw 			sa_free_attr_string(id);
691*5331Samw 		}
692*5331Samw 	}
693*5331Samw 	return (found);
694*5331Samw }
695*5331Samw 
696*5331Samw /*
697*5331Samw  * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
6983034Sdougm  *
6994653Sdougm  * Extract share properties from the SMF property group. More sanity
7003034Sdougm  * checks are done and the share object is created. We ignore some
7013034Sdougm  * errors that could exist in the repository and only worry about
7023034Sdougm  * property groups that validate in naming.
7033034Sdougm  */
7043034Sdougm 
7053034Sdougm static int
7063034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
7073910Sdougm 			scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
7083034Sdougm {
7093034Sdougm 	xmlNodePtr node;
7104653Sdougm 	char *name = NULL;
7114653Sdougm 	scf_iter_t *iter = NULL;
7124653Sdougm 	scf_property_t *prop = NULL;
7134653Sdougm 	scf_value_t *value = NULL;
7143034Sdougm 	ssize_t vallen;
7154653Sdougm 	char *valuestr = NULL;
7163034Sdougm 	int ret = SA_OK;
7173034Sdougm 	char *sectype = NULL;
7183034Sdougm 	char *proto;
7193034Sdougm 	sa_share_t share;
7204653Sdougm 	uuid_t uuid;
7213034Sdougm 
7223034Sdougm 	/*
7233034Sdougm 	 * While preliminary check (starts with 'S') passed before
7243034Sdougm 	 * getting here. Need to make sure it is in ID syntax
7253034Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
7263034Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
7273034Sdougm 	 * characters, it is likely one of the protocol/security
7283034Sdougm 	 * versions.
7293034Sdougm 	 */
7303034Sdougm 	vallen = strlen(id);
7314653Sdougm 	if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
7324653Sdougm 		/*
7334653Sdougm 		 * It is ok to not have what we thought since someone might
7344653Sdougm 		 * have added a name via SMF.
7354653Sdougm 		 */
7364653Sdougm 		return (ret);
7374653Sdougm 	}
7384653Sdougm 	if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
7393034Sdougm 		proto = strchr(id, '_');
7403034Sdougm 		if (proto == NULL)
7414653Sdougm 			return (ret);
7423034Sdougm 		*proto++ = '\0';
7433034Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
7444653Sdougm 			return (ret);
7453034Sdougm 		/*
7463034Sdougm 		 * probably a legal optionset so check a few more
7473034Sdougm 		 * syntax points below.
7483034Sdougm 		 */
7493034Sdougm 		if (*proto == '\0') {
7504653Sdougm 			/* not a valid proto (null) */
7514653Sdougm 			return (ret);
7523034Sdougm 		}
753*5331Samw 
7543034Sdougm 		sectype = strchr(proto, '_');
7553034Sdougm 		if (sectype != NULL)
7564653Sdougm 			*sectype++ = '\0';
7573034Sdougm 		if (!valid_protocol(proto))
7584653Sdougm 			return (ret);
7593034Sdougm 	}
7603034Sdougm 
7613034Sdougm 	/*
7624653Sdougm 	 * To get here, we have a valid protocol and possibly a
7633034Sdougm 	 * security. We now have to find the share that it is really
7643034Sdougm 	 * associated with. The "id" portion of the pgroup name will
7653034Sdougm 	 * match.
7663034Sdougm 	 */
7673034Sdougm 
7683910Sdougm 	share = find_share_by_id(sahandle, id);
7693034Sdougm 	if (share == NULL)
7704653Sdougm 		return (SA_BAD_PATH);
7713034Sdougm 
7723034Sdougm 	root = (xmlNodePtr)share;
7733034Sdougm 
7743034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
7753034Sdougm 
7764653Sdougm 	if (sectype == NULL)
7774653Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
7784653Sdougm 	else {
779*5331Samw 		if (isdigit((int)*sectype)) {
780*5331Samw 			sa_resource_t resource;
781*5331Samw 			/*
782*5331Samw 			 * If sectype[0] is a digit, then it is an index into
783*5331Samw 			 * the resource names. We need to find a resource
784*5331Samw 			 * record and then get the properties into an
785*5331Samw 			 * optionset. The optionset becomes the "node" and the
786*5331Samw 			 * rest is hung off of the share.
787*5331Samw 			 */
788*5331Samw 			resource = find_resource_by_index(share, sectype);
789*5331Samw 			if (resource != NULL) {
790*5331Samw 				node = xmlNewChild(resource, NULL,
791*5331Samw 				    (xmlChar *)"optionset", NULL);
792*5331Samw 			} else {
793*5331Samw 				/* this shouldn't happen */
794*5331Samw 				ret = SA_SYSTEM_ERR;
795*5331Samw 			}
796*5331Samw 		} else {
797*5331Samw 			/*
798*5331Samw 			 * If not a digit, then it is a security type
799*5331Samw 			 * (alternate option space). Security types start with
800*5331Samw 			 * an alphabetic.
801*5331Samw 			 */
802*5331Samw 			node = xmlNewChild(root, NULL, (xmlChar *)"security",
803*5331Samw 			    NULL);
804*5331Samw 			if (node != NULL)
805*5331Samw 				xmlSetProp(node, (xmlChar *)"sectype",
806*5331Samw 				    (xmlChar *)sectype);
807*5331Samw 		}
8084653Sdougm 	}
8094653Sdougm 	if (node == NULL) {
8104653Sdougm 		ret = SA_NO_MEMORY;
8114653Sdougm 		goto out;
8124653Sdougm 	}
8134653Sdougm 
8144653Sdougm 	xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
8154653Sdougm 	/* now find the properties */
8163034Sdougm 	iter = scf_iter_create(handle->handle);
8173034Sdougm 	value = scf_value_create(handle->handle);
8183034Sdougm 	prop = scf_property_create(handle->handle);
8193034Sdougm 	name = malloc(scf_max_name_len);
8203034Sdougm 	valuestr = malloc(vallen);
8213034Sdougm 
8224653Sdougm 	if (iter == NULL || value == NULL || prop == NULL || name == NULL)
8234653Sdougm 		goto out;
8244653Sdougm 
825*5331Samw 	/* iterate over the share pg properties */
8264653Sdougm 	if (scf_iter_pg_properties(iter, pg) == 0) {
8274653Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
8283034Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
8293034Sdougm 			if (scf_property_get_name(prop, name,
8304653Sdougm 			    scf_max_name_len) > 0) {
8314653Sdougm 				if (scf_property_get_value(prop, value) == 0) {
8324653Sdougm 					if (scf_value_get_astring(value,
8334653Sdougm 					    valuestr, vallen) >= 0) {
8344653Sdougm 						ret = SA_OK;
8354653Sdougm 					}
8363034Sdougm 				}
8373034Sdougm 			} else {
8384653Sdougm 				ret = SA_SYSTEM_ERR;
8393034Sdougm 			}
8403034Sdougm 			if (ret == SA_OK) {
8414653Sdougm 				sa_property_t prop;
8424653Sdougm 				prop = sa_create_property(name, valuestr);
8434653Sdougm 				if (prop != NULL)
8444653Sdougm 					prop = (sa_property_t)xmlAddChild(node,
8454653Sdougm 					    (xmlNodePtr)prop);
8464653Sdougm 				else
8474653Sdougm 					ret = SA_NO_MEMORY;
8483034Sdougm 			}
8493034Sdougm 		}
8503034Sdougm 	} else {
8514653Sdougm 		ret = SA_SYSTEM_ERR;
8523034Sdougm 	}
8534653Sdougm out:
8543034Sdougm 	if (iter != NULL)
8554653Sdougm 		scf_iter_destroy(iter);
8563034Sdougm 	if (value != NULL)
8574653Sdougm 		scf_value_destroy(value);
8583034Sdougm 	if (prop != NULL)
8594653Sdougm 		scf_property_destroy(prop);
8603034Sdougm 	if (name != NULL)
8614653Sdougm 		free(name);
8623034Sdougm 	if (valuestr != NULL)
8634653Sdougm 		free(valuestr);
8643034Sdougm 	return (ret);
8653034Sdougm }
8663034Sdougm 
8673034Sdougm /*
8683034Sdougm  * sa_extract_group(root, handle, instance)
8693034Sdougm  *
8704653Sdougm  * Get the config info for this instance of a group and create the XML
8713034Sdougm  * subtree from it.
8723034Sdougm  */
8733034Sdougm 
8743034Sdougm static int
8753034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
8763910Sdougm 			scf_instance_t *instance, sa_handle_t sahandle)
8773034Sdougm {
8783034Sdougm 	char *buff;
8793034Sdougm 	xmlNodePtr node;
8803034Sdougm 	scf_iter_t *iter;
8813034Sdougm 	char *proto;
8823034Sdougm 	char *sectype;
8833034Sdougm 	int have_shares = 0;
8843034Sdougm 	int has_proto = 0;
8853034Sdougm 	int is_default = 0;
8863034Sdougm 	int ret = SA_OK;
8873034Sdougm 	int err;
8883034Sdougm 
8893034Sdougm 	buff = malloc(scf_max_name_len);
8904653Sdougm 	if (buff == NULL)
8914653Sdougm 		return (SA_NO_MEMORY);
8924653Sdougm 
8933034Sdougm 	iter = scf_iter_create(handle->handle);
8944653Sdougm 	if (iter == NULL) {
8954653Sdougm 		ret = SA_NO_MEMORY;
8964653Sdougm 		goto out;
8974653Sdougm 	}
8984653Sdougm 
8994653Sdougm 	if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
9003034Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
9014653Sdougm 		if (node == NULL) {
9024653Sdougm 			ret = SA_NO_MEMORY;
9034653Sdougm 			goto out;
9044653Sdougm 		}
9054653Sdougm 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
9064653Sdougm 		if (strcmp(buff, "default") == 0)
9073034Sdougm 			is_default++;
9084653Sdougm 
9094653Sdougm 		sa_extract_attrs(node, handle, instance);
9104653Sdougm 		/*
9114653Sdougm 		 * Iterate through all the property groups
9124653Sdougm 		 * looking for those with security or
9134653Sdougm 		 * optionset prefixes. The names of the
9144653Sdougm 		 * matching pgroups are parsed to get the
9154653Sdougm 		 * protocol, and for security, the sectype.
9164653Sdougm 		 * Syntax is as follows:
9174653Sdougm 		 *    optionset | optionset_<proto>
9184653Sdougm 		 *    security_default | security_<proto>_<sectype>
9194653Sdougm 		 * "operation" is handled by
9204653Sdougm 		 * sa_extract_attrs().
9214653Sdougm 		 */
9224653Sdougm 		if (scf_iter_instance_pgs(iter, instance) != 0) {
9234653Sdougm 			ret = SA_NO_MEMORY;
9244653Sdougm 			goto out;
9254653Sdougm 		}
9264653Sdougm 		while (scf_iter_next_pg(iter, handle->pg) > 0) {
9274653Sdougm 			/* Have a pgroup so sort it out */
9284653Sdougm 			ret = scf_pg_get_name(handle->pg, buff,
9294653Sdougm 			    scf_max_name_len);
9304653Sdougm 			if (ret  > 0) {
9314653Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
9323034Sdougm 					sa_share_from_pgroup(node, handle,
9334653Sdougm 					    handle->pg, buff);
9343034Sdougm 					have_shares++;
9354653Sdougm 				} else if (strncmp(buff, "optionset", 9) ==
9364653Sdougm 				    0) {
9373034Sdougm 					char *nodetype = "optionset";
9384653Sdougm 					/* Have an optionset */
9393034Sdougm 					sectype = NULL;
9403034Sdougm 					proto = strchr(buff, '_');
9413034Sdougm 					if (proto != NULL) {
9424653Sdougm 						*proto++ = '\0';
9434653Sdougm 						sectype = strchr(proto, '_');
9444653Sdougm 						if (sectype != NULL) {
9454653Sdougm 							*sectype++ = '\0';
9464653Sdougm 							nodetype = "security";
9474653Sdougm 						}
9483034Sdougm 					}
9493034Sdougm 					ret = sa_extract_pgroup(node, handle,
9504653Sdougm 					    handle->pg, nodetype, proto,
9514653Sdougm 					    sectype);
9523034Sdougm 					has_proto++;
9534653Sdougm 				} else if (strncmp(buff, "security", 8) == 0) {
9543034Sdougm 					/*
9554653Sdougm 					 * Have a security (note that
9563034Sdougm 					 * this should change in the
9573034Sdougm 					 * future)
9583034Sdougm 					 */
9593034Sdougm 					proto = strchr(buff, '_');
9603034Sdougm 					sectype = NULL;
9613034Sdougm 					if (proto != NULL) {
9624653Sdougm 						*proto++ = '\0';
9634653Sdougm 						sectype = strchr(proto, '_');
9644653Sdougm 						if (sectype != NULL)
9654653Sdougm 							*sectype++ = '\0';
9664653Sdougm 						if (strcmp(proto, "default") ==
9674653Sdougm 						    0)
9684653Sdougm 							proto = NULL;
9693034Sdougm 					}
9703034Sdougm 					ret = sa_extract_pgroup(node, handle,
9714653Sdougm 					    handle->pg, "security", proto,
9724653Sdougm 					    sectype);
9733034Sdougm 					has_proto++;
9743034Sdougm 				}
9754653Sdougm 				/* Ignore everything else */
9763034Sdougm 			}
9774653Sdougm 		}
9784653Sdougm 		/*
9794653Sdougm 		 * Make sure we have a valid default group.
9804653Sdougm 		 * On first boot, default won't have any
9814653Sdougm 		 * protocols defined and won't be enabled (but
9824653Sdougm 		 * should be).
9834653Sdougm 		 */
9844653Sdougm 		if (is_default) {
9854653Sdougm 			char *state = sa_get_group_attr((sa_group_t)node,
9864653Sdougm 			    "state");
9874653Sdougm 			char **protos;
9884653Sdougm 			int numprotos;
9894653Sdougm 			int i;
9903034Sdougm 
9914653Sdougm 			if (state == NULL) {
9923034Sdougm 				/* set attribute to enabled */
9933034Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
9944653Sdougm 				    "state", "enabled");
9954653Sdougm 				/* We can assume no protocols */
9963034Sdougm 				numprotos = sa_get_protocols(&protos);
9973034Sdougm 				for (i = 0; i < numprotos; i++)
9984653Sdougm 					(void) sa_create_optionset(
9994653Sdougm 					    (sa_group_t)node, protos[i]);
10003034Sdougm 				if (numprotos > 0)
10014653Sdougm 					free(protos);
10024653Sdougm 			} else {
10033034Sdougm 				sa_free_attr_string(state);
10043034Sdougm 			}
10054653Sdougm 		}
10064653Sdougm 		/* Do a second pass if shares were found */
10074653Sdougm 		if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
10084653Sdougm 			while (scf_iter_next_pg(iter, handle->pg) > 0) {
10093034Sdougm 				/*
10104653Sdougm 				 * Have a pgroup so see if it is a
10113034Sdougm 				 * share optionset
10123034Sdougm 				 */
10133034Sdougm 				err = scf_pg_get_name(handle->pg, buff,
10144653Sdougm 				    scf_max_name_len);
10154653Sdougm 				if (err  <= 0)
10164653Sdougm 					continue;
10174653Sdougm 				if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
10183034Sdougm 					ret = sa_share_props_from_pgroup(node,
10194653Sdougm 					    handle, handle->pg, buff,
10204653Sdougm 					    sahandle);
10213034Sdougm 				}
10223034Sdougm 			}
10233034Sdougm 		}
10243034Sdougm 	}
10254653Sdougm out:
10263034Sdougm 	if (iter != NULL)
10274653Sdougm 		scf_iter_destroy(iter);
10283034Sdougm 	if (buff != NULL)
10294653Sdougm 		free(buff);
10303034Sdougm 	return (ret);
10313034Sdougm }
10323034Sdougm 
10333034Sdougm /*
10343034Sdougm  * sa_extract_defaults(root, handle, instance)
10353034Sdougm  *
10364653Sdougm  * Local function to find the default properties that live in the
1037*5331Samw  * default instance's "operation" property group.
10383034Sdougm  */
10393034Sdougm 
10403034Sdougm static void
10413034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
10423034Sdougm 		    scf_instance_t *instance)
10433034Sdougm {
10443034Sdougm 	xmlNodePtr node;
10453034Sdougm 	scf_property_t *prop;
10463034Sdougm 	scf_value_t *value;
10473034Sdougm 	char *valuestr;
10483034Sdougm 	ssize_t vallen;
10493034Sdougm 
10503034Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
10513034Sdougm 	prop = scf_property_create(handle->handle);
10523034Sdougm 	value = scf_value_create(handle->handle);
10533034Sdougm 	valuestr = malloc(vallen);
10544653Sdougm 
10554653Sdougm 	if (prop == NULL || value == NULL || vallen == 0 ||
10564653Sdougm 	    scf_instance_get_pg(instance, "operation", handle->pg) != 0)
10574653Sdougm 		goto out;
10584653Sdougm 
10594653Sdougm 	if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
10604653Sdougm 		goto out;
10614653Sdougm 
10624653Sdougm 	/* Found the property so get the value */
10634653Sdougm 	if (scf_property_get_value(prop, value) == 0) {
10644653Sdougm 		if (scf_value_get_astring(value, valuestr, vallen) > 0) {
10653034Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
10664653Sdougm 			    NULL);
10673034Sdougm 			if (node != NULL) {
10684653Sdougm 				xmlSetProp(node, (xmlChar *)"timestamp",
10694653Sdougm 				    (xmlChar *)valuestr);
10704653Sdougm 				xmlSetProp(node, (xmlChar *)"path",
10714653Sdougm 				    (xmlChar *)SA_LEGACY_DFSTAB);
10723034Sdougm 			}
10733034Sdougm 		}
10743034Sdougm 	}
10754653Sdougm out:
10763034Sdougm 	if (valuestr != NULL)
10774653Sdougm 		free(valuestr);
10783034Sdougm 	if (value != NULL)
10794653Sdougm 		scf_value_destroy(value);
10803034Sdougm 	if (prop != NULL)
10814653Sdougm 		scf_property_destroy(prop);
10823034Sdougm }
10833034Sdougm 
10843034Sdougm 
10853034Sdougm /*
1086*5331Samw  * sa_get_config(handle, root, doc, sahandle)
10873034Sdougm  *
10884653Sdougm  * Walk the SMF repository for /network/shares/group and find all the
10893034Sdougm  * instances. These become group names.  Then add the XML structure
10903034Sdougm  * below the groups based on property groups and properties.
10913034Sdougm  */
10923034Sdougm int
10933973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
10943034Sdougm {
10953034Sdougm 	int ret = SA_OK;
10963034Sdougm 	scf_instance_t *instance;
10973034Sdougm 	scf_iter_t *iter;
10983034Sdougm 	char buff[BUFSIZ * 2];
10993034Sdougm 
11003034Sdougm 	instance = scf_instance_create(handle->handle);
11013034Sdougm 	iter = scf_iter_create(handle->handle);
11023973Sdougm 	if (instance != NULL && iter != NULL) {
11034653Sdougm 		if ((ret = scf_iter_service_instances(iter,
11044653Sdougm 		    handle->service)) == 0) {
11054653Sdougm 			while ((ret = scf_iter_next_instance(iter,
11064653Sdougm 			    instance)) > 0) {
11074653Sdougm 				if (scf_instance_get_name(instance, buff,
11084653Sdougm 				    sizeof (buff)) > 0) {
11094653Sdougm 					if (strcmp(buff, "default") == 0)
11104653Sdougm 						sa_extract_defaults(root,
11114653Sdougm 						    handle, instance);
11124653Sdougm 					ret = sa_extract_group(root, handle,
11134653Sdougm 					    instance, sahandle);
11144653Sdougm 				}
11154653Sdougm 			}
11163034Sdougm 		}
11173034Sdougm 	}
11183973Sdougm 
11194653Sdougm 	/* Always cleanup these */
11203034Sdougm 	if (instance != NULL)
11214653Sdougm 		scf_instance_destroy(instance);
11223034Sdougm 	if (iter != NULL)
11234653Sdougm 		scf_iter_destroy(iter);
11243034Sdougm 	return (ret);
11253034Sdougm }
11263034Sdougm 
11273034Sdougm /*
11283034Sdougm  * sa_get_instance(handle, instance)
11293034Sdougm  *
11304653Sdougm  * Get the instance of the group service. This is actually the
11313034Sdougm  * specific group name. The instance is needed for all property and
11323034Sdougm  * control operations.
11333034Sdougm  */
11343034Sdougm 
11353034Sdougm int
11363034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
11373034Sdougm {
11383034Sdougm 	if (scf_service_get_instance(handle->service, instname,
11394653Sdougm 	    handle->instance) != 0) {
11404653Sdougm 		return (SA_NO_SUCH_GROUP);
11413034Sdougm 	}
11423034Sdougm 	return (SA_OK);
11433034Sdougm }
11443034Sdougm 
11453034Sdougm /*
11463034Sdougm  * sa_create_instance(handle, instname)
11473034Sdougm  *
11483034Sdougm  * Create a new SMF service instance. There can only be one with a
11493034Sdougm  * given name.
11503034Sdougm  */
11513034Sdougm 
11523034Sdougm int
11533034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
11543034Sdougm {
11553034Sdougm 	int ret = SA_OK;
11563034Sdougm 	char instance[SA_GROUP_INST_LEN];
11573034Sdougm 	if (scf_service_add_instance(handle->service, instname,
11584653Sdougm 	    handle->instance) != 0) {
11593034Sdougm 	/* better error returns need to be added based on real error */
11604653Sdougm 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
11614653Sdougm 			ret = SA_NO_PERMISSION;
11624653Sdougm 		else
11634653Sdougm 			ret = SA_DUPLICATE_NAME;
11643034Sdougm 	} else {
11654653Sdougm 		/* have the service created, so enable it */
11664653Sdougm 		(void) snprintf(instance, sizeof (instance), "%s:%s",
11674653Sdougm 		    SA_SVC_FMRI_BASE, instname);
11684653Sdougm 		(void) smf_enable_instance(instance, 0);
11693034Sdougm 	}
11703034Sdougm 	return (ret);
11713034Sdougm }
11723034Sdougm 
11733034Sdougm /*
11743034Sdougm  * sa_delete_instance(handle, instname)
11753034Sdougm  *
11763034Sdougm  * When a group goes away, we also remove the service instance.
11773034Sdougm  */
11783034Sdougm 
11793034Sdougm int
11803034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
11813034Sdougm {
11823034Sdougm 	int ret;
11833034Sdougm 
11843034Sdougm 	if (strcmp(instname, "default") == 0) {
11854653Sdougm 		ret = SA_NO_PERMISSION;
11863034Sdougm 	} else {
11874653Sdougm 		if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
11884653Sdougm 			if (scf_instance_delete(handle->instance) != 0)
11894653Sdougm 				/* need better analysis */
11904653Sdougm 				ret = SA_NO_PERMISSION;
11914653Sdougm 		}
11923034Sdougm 	}
11933034Sdougm 	return (ret);
11943034Sdougm }
11953034Sdougm 
11963034Sdougm /*
11973034Sdougm  * sa_create_pgroup(handle, pgroup)
11983034Sdougm  *
11993034Sdougm  * create a new property group
12003034Sdougm  */
12013034Sdougm 
12023034Sdougm int
12033034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
12043034Sdougm {
12053034Sdougm 	int ret = SA_OK;
12063034Sdougm 	/*
12074653Sdougm 	 * Only create a handle if it doesn't exist. It is ok to exist
12083034Sdougm 	 * since the pg handle will be set as a side effect.
12093034Sdougm 	 */
12104653Sdougm 	if (handle->pg == NULL)
12114653Sdougm 		handle->pg = scf_pg_create(handle->handle);
12124653Sdougm 
12133034Sdougm 	/*
12144653Sdougm 	 * If the pgroup exists, we are done. If it doesn't, then we
12153034Sdougm 	 * need to actually add one to the service instance.
12163034Sdougm 	 */
12173034Sdougm 	if (scf_instance_get_pg(handle->instance,
12184653Sdougm 	    pgroup, handle->pg) != 0) {
12194653Sdougm 		/* Doesn't exist so create one */
12204653Sdougm 		if (scf_instance_add_pg(handle->instance, pgroup,
12214653Sdougm 		    SCF_GROUP_APPLICATION, 0, handle->pg) != 0) {
12224653Sdougm 			switch (scf_error()) {
12234653Sdougm 			case SCF_ERROR_PERMISSION_DENIED:
12244653Sdougm 				ret = SA_NO_PERMISSION;
12254653Sdougm 				break;
12264653Sdougm 			default:
12274653Sdougm 				ret = SA_SYSTEM_ERR;
12284653Sdougm 				break;
12294653Sdougm 			}
12303034Sdougm 		}
12313034Sdougm 	}
12323034Sdougm 	return (ret);
12333034Sdougm }
12343034Sdougm 
12353034Sdougm /*
12363034Sdougm  * sa_delete_pgroup(handle, pgroup)
12373034Sdougm  *
12384653Sdougm  * Remove the property group from the current instance of the service,
12393034Sdougm  * but only if it actually exists.
12403034Sdougm  */
12413034Sdougm 
12423034Sdougm int
12433034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
12443034Sdougm {
12453034Sdougm 	int ret = SA_OK;
12463034Sdougm 	/*
12474653Sdougm 	 * Only delete if it does exist.
12483034Sdougm 	 */
12494653Sdougm 	if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
12504653Sdougm 		/* does exist so delete it */
12514653Sdougm 		if (scf_pg_delete(handle->pg) != 0)
12524653Sdougm 			ret = SA_SYSTEM_ERR;
12534653Sdougm 	} else {
12543034Sdougm 		ret = SA_SYSTEM_ERR;
12553034Sdougm 	}
12563034Sdougm 	if (ret == SA_SYSTEM_ERR &&
12573034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
12583034Sdougm 		ret = SA_NO_PERMISSION;
12593034Sdougm 	}
12603034Sdougm 	return (ret);
12613034Sdougm }
12623034Sdougm 
12633034Sdougm /*
12643034Sdougm  * sa_start_transaction(handle, pgroup)
12653034Sdougm  *
12663034Sdougm  * Start an SMF transaction so we can deal with properties. it would
12673034Sdougm  * be nice to not have to expose this, but we have to in order to
12683034Sdougm  * optimize.
12693034Sdougm  *
12703034Sdougm  * Basic model is to hold the transaction in the handle and allow
12713034Sdougm  * property adds/deletes/updates to be added then close the
12723034Sdougm  * transaction (or abort).  There may eventually be a need to handle
12733034Sdougm  * other types of transaction mechanisms but we don't do that now.
12743034Sdougm  *
12753034Sdougm  * An sa_start_transaction must be followed by either an
12763034Sdougm  * sa_end_transaction or sa_abort_transaction before another
12773034Sdougm  * sa_start_transaction can be done.
12783034Sdougm  */
12793034Sdougm 
12803034Sdougm int
12813034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
12823034Sdougm {
12833034Sdougm 	int ret = SA_OK;
12843034Sdougm 	/*
12854653Sdougm 	 * Lookup the property group and create it if it doesn't already
12863034Sdougm 	 * exist.
12873034Sdougm 	 */
12883034Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
12894653Sdougm 		ret = sa_create_pgroup(handle, propgroup);
12904653Sdougm 		if (ret == SA_OK) {
12914653Sdougm 			handle->trans = scf_transaction_create(handle->handle);
12924653Sdougm 			if (handle->trans != NULL) {
12934653Sdougm 				if (scf_transaction_start(handle->trans,
12944653Sdougm 				    handle->pg) != 0) {
12954653Sdougm 					ret = SA_SYSTEM_ERR;
12964653Sdougm 				}
12974653Sdougm 				if (ret != SA_OK) {
12984653Sdougm 					scf_transaction_destroy(handle->trans);
12994653Sdougm 					handle->trans = NULL;
13004653Sdougm 				}
13014653Sdougm 			} else {
13024653Sdougm 				ret = SA_SYSTEM_ERR;
13034653Sdougm 			}
13043034Sdougm 		}
13053034Sdougm 	}
13063034Sdougm 	if (ret == SA_SYSTEM_ERR &&
13073034Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
13083034Sdougm 		ret = SA_NO_PERMISSION;
13093034Sdougm 	}
13103034Sdougm 	return (ret);
13113034Sdougm }
13123034Sdougm 
13133034Sdougm /*
13143034Sdougm  * sa_end_transaction(handle)
13153034Sdougm  *
13163034Sdougm  * Commit the changes that were added to the transaction in the
13173034Sdougm  * handle. Do all necessary cleanup.
13183034Sdougm  */
13193034Sdougm 
13203034Sdougm int
13213034Sdougm sa_end_transaction(scfutilhandle_t *handle)
13223034Sdougm {
13233034Sdougm 	int ret = SA_OK;
13243034Sdougm 
13253034Sdougm 	if (handle->trans == NULL) {
13264653Sdougm 		ret = SA_SYSTEM_ERR;
13273034Sdougm 	} else {
13284653Sdougm 		if (scf_transaction_commit(handle->trans) < 0)
13294653Sdougm 			ret = SA_SYSTEM_ERR;
13304653Sdougm 		scf_transaction_destroy_children(handle->trans);
13314653Sdougm 		scf_transaction_destroy(handle->trans);
13324653Sdougm 		handle->trans = NULL;
13333034Sdougm 	}
13343034Sdougm 	return (ret);
13353034Sdougm }
13363034Sdougm 
13373034Sdougm /*
13383034Sdougm  * sa_abort_transaction(handle)
13393034Sdougm  *
13403034Sdougm  * Abort the changes that were added to the transaction in the
13413034Sdougm  * handle. Do all necessary cleanup.
13423034Sdougm  */
13433034Sdougm 
13443034Sdougm void
13453034Sdougm sa_abort_transaction(scfutilhandle_t *handle)
13463034Sdougm {
13473034Sdougm 	if (handle->trans != NULL) {
13484653Sdougm 		scf_transaction_reset_all(handle->trans);
13494653Sdougm 		scf_transaction_destroy_children(handle->trans);
13504653Sdougm 		scf_transaction_destroy(handle->trans);
13514653Sdougm 		handle->trans = NULL;
13523034Sdougm 	}
13533034Sdougm }
13543034Sdougm 
13553034Sdougm /*
13563034Sdougm  * sa_set_property(handle, prop, value)
13573034Sdougm  *
13584653Sdougm  * Set a property transaction entry into the pending SMF transaction.
13593034Sdougm  */
13603034Sdougm 
13613034Sdougm int
13623034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
13633034Sdougm {
13643034Sdougm 	int ret = SA_OK;
13653034Sdougm 	scf_value_t *value;
13663034Sdougm 	scf_transaction_entry_t *entry;
13673034Sdougm 	/*
13684653Sdougm 	 * Properties must be set in transactions and don't take
13693034Sdougm 	 * effect until the transaction has been ended/committed.
13703034Sdougm 	 */
13713034Sdougm 	value = scf_value_create(handle->handle);
13723034Sdougm 	entry = scf_entry_create(handle->handle);
13733034Sdougm 	if (value != NULL && entry != NULL) {
13744653Sdougm 		if (scf_transaction_property_change(handle->trans, entry,
13754653Sdougm 		    propname, SCF_TYPE_ASTRING) == 0 ||
13764653Sdougm 		    scf_transaction_property_new(handle->trans, entry,
13774653Sdougm 		    propname, SCF_TYPE_ASTRING) == 0) {
13784653Sdougm 			if (scf_value_set_astring(value, valstr) == 0) {
13794653Sdougm 				if (scf_entry_add_value(entry, value) != 0) {
13804653Sdougm 					ret = SA_SYSTEM_ERR;
13814653Sdougm 					scf_value_destroy(value);
13824653Sdougm 				}
13834653Sdougm 				/* The value is in the transaction */
13844653Sdougm 				value = NULL;
13854653Sdougm 			} else {
13864653Sdougm 				/* Value couldn't be constructed */
13874653Sdougm 				ret = SA_SYSTEM_ERR;
13884653Sdougm 			}
13894653Sdougm 			/* The entry is in the transaction */
13904653Sdougm 			entry = NULL;
13914653Sdougm 		} else {
13923034Sdougm 			ret = SA_SYSTEM_ERR;
13933034Sdougm 		}
13944653Sdougm 	} else {
13953034Sdougm 		ret = SA_SYSTEM_ERR;
13963034Sdougm 	}
13973034Sdougm 	if (ret == SA_SYSTEM_ERR) {
13984653Sdougm 		switch (scf_error()) {
13994653Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
14004653Sdougm 			ret = SA_NO_PERMISSION;
14014653Sdougm 			break;
14024653Sdougm 		}
14033034Sdougm 	}
14043034Sdougm 	/*
14054653Sdougm 	 * Cleanup if there were any errors that didn't leave these
14063034Sdougm 	 * values where they would be cleaned up later.
14073034Sdougm 	 */
14083034Sdougm 	if (value != NULL)
14094653Sdougm 		scf_value_destroy(value);
14103034Sdougm 	if (entry != NULL)
14114653Sdougm 		scf_entry_destroy(entry);
14123034Sdougm 	return (ret);
14133034Sdougm }
14143034Sdougm 
14153034Sdougm /*
1416*5331Samw  * check_resource(share)
1417*5331Samw  *
1418*5331Samw  * Check to see if share has any persistent resources. We don't want
1419*5331Samw  * to save if they are all transient.
1420*5331Samw  */
1421*5331Samw static int
1422*5331Samw check_resource(sa_share_t share)
1423*5331Samw {
1424*5331Samw 	sa_resource_t resource;
1425*5331Samw 	int ret = B_FALSE;
1426*5331Samw 
1427*5331Samw 	for (resource = sa_get_share_resource(share, NULL);
1428*5331Samw 	    resource != NULL && ret == B_FALSE;
1429*5331Samw 	    resource = sa_get_next_resource(resource)) {
1430*5331Samw 		char *type;
1431*5331Samw 		type = sa_get_resource_attr(resource, "type");
1432*5331Samw 		if (type != NULL) {
1433*5331Samw 			if (strcmp(type, "transient") != 0) {
1434*5331Samw 				ret = B_TRUE;
1435*5331Samw 			}
1436*5331Samw 			sa_free_attr_string(type);
1437*5331Samw 		}
1438*5331Samw 	}
1439*5331Samw 	return (ret);
1440*5331Samw }
1441*5331Samw 
1442*5331Samw /*
1443*5331Samw  * sa_set_resource_property(handle, prop, value)
1444*5331Samw  *
1445*5331Samw  * set a property transaction entry into the pending SMF
1446*5331Samw  * transaction. We don't want to include any transient resources
1447*5331Samw  */
1448*5331Samw 
1449*5331Samw static int
1450*5331Samw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
1451*5331Samw {
1452*5331Samw 	int ret = SA_OK;
1453*5331Samw 	scf_value_t *value;
1454*5331Samw 	scf_transaction_entry_t *entry;
1455*5331Samw 	sa_resource_t resource;
1456*5331Samw 	char *valstr;
1457*5331Samw 	char *idstr;
1458*5331Samw 	char *description;
1459*5331Samw 	char *propstr = NULL;
1460*5331Samw 	size_t strsize;
1461*5331Samw 
1462*5331Samw 	/* don't bother if no persistent resources */
1463*5331Samw 	if (check_resource(share) == B_FALSE)
1464*5331Samw 		return (ret);
1465*5331Samw 
1466*5331Samw 	/*
1467*5331Samw 	 * properties must be set in transactions and don't take
1468*5331Samw 	 * effect until the transaction has been ended/committed.
1469*5331Samw 	 */
1470*5331Samw 	entry = scf_entry_create(handle->handle);
1471*5331Samw 	if (entry == NULL)
1472*5331Samw 		return (SA_SYSTEM_ERR);
1473*5331Samw 
1474*5331Samw 	if (scf_transaction_property_change(handle->trans, entry,
1475*5331Samw 	    "resource",	SCF_TYPE_ASTRING) != 0 &&
1476*5331Samw 	    scf_transaction_property_new(handle->trans, entry,
1477*5331Samw 	    "resource", SCF_TYPE_ASTRING) != 0) {
1478*5331Samw 		scf_entry_destroy(entry);
1479*5331Samw 		return (SA_SYSTEM_ERR);
1480*5331Samw 
1481*5331Samw 	}
1482*5331Samw 	for (resource = sa_get_share_resource(share, NULL);
1483*5331Samw 	    resource != NULL;
1484*5331Samw 	    resource = sa_get_next_resource(resource)) {
1485*5331Samw 		value = scf_value_create(handle->handle);
1486*5331Samw 		if (value == NULL) {
1487*5331Samw 			ret = SA_NO_MEMORY;
1488*5331Samw 			break;
1489*5331Samw 		}
1490*5331Samw 			/* Get size of complete string */
1491*5331Samw 		valstr = sa_get_resource_attr(resource, "name");
1492*5331Samw 		idstr = sa_get_resource_attr(resource, "id");
1493*5331Samw 		description = sa_get_resource_description(resource);
1494*5331Samw 		strsize = (valstr != NULL) ? strlen(valstr) : 0;
1495*5331Samw 		strsize += (idstr != NULL) ? strlen(idstr) : 0;
1496*5331Samw 		strsize += (description != NULL) ? strlen(description) : 0;
1497*5331Samw 		if (strsize > 0) {
1498*5331Samw 			strsize += 3; /* add nul and ':' */
1499*5331Samw 			propstr = (char *)malloc(strsize);
1500*5331Samw 			if (propstr == NULL) {
1501*5331Samw 				scf_value_destroy(value);
1502*5331Samw 				ret = SA_NO_MEMORY;
1503*5331Samw 				goto err;
1504*5331Samw 			}
1505*5331Samw 			if (idstr == NULL)
1506*5331Samw 				(void) snprintf(propstr, strsize, "%s",
1507*5331Samw 				    valstr ? valstr : "");
1508*5331Samw 			else
1509*5331Samw 				(void) snprintf(propstr, strsize, "%s:%s:%s",
1510*5331Samw 				    idstr ? idstr : "", valstr ? valstr : "",
1511*5331Samw 				    description ? description : "");
1512*5331Samw 			if (scf_value_set_astring(value, propstr) != 0) {
1513*5331Samw 				ret = SA_SYSTEM_ERR;
1514*5331Samw 				free(propstr);
1515*5331Samw 				scf_value_destroy(value);
1516*5331Samw 				break;
1517*5331Samw 			}
1518*5331Samw 			if (scf_entry_add_value(entry, value) != 0) {
1519*5331Samw 				ret = SA_SYSTEM_ERR;
1520*5331Samw 				free(propstr);
1521*5331Samw 				scf_value_destroy(value);
1522*5331Samw 				break;
1523*5331Samw 			}
1524*5331Samw 			/* the value is in the transaction */
1525*5331Samw 			value = NULL;
1526*5331Samw 			free(propstr);
1527*5331Samw 		}
1528*5331Samw err:
1529*5331Samw 		if (valstr != NULL)
1530*5331Samw 			sa_free_attr_string(valstr);
1531*5331Samw 		if (idstr != NULL)
1532*5331Samw 			sa_free_attr_string(idstr);
1533*5331Samw 		if (description != NULL)
1534*5331Samw 			sa_free_share_description(description);
1535*5331Samw 	}
1536*5331Samw 	/* the entry is in the transaction */
1537*5331Samw 	entry = NULL;
1538*5331Samw 
1539*5331Samw 	if (ret == SA_SYSTEM_ERR) {
1540*5331Samw 		switch (scf_error()) {
1541*5331Samw 		case SCF_ERROR_PERMISSION_DENIED:
1542*5331Samw 			ret = SA_NO_PERMISSION;
1543*5331Samw 			break;
1544*5331Samw 		}
1545*5331Samw 	}
1546*5331Samw 	/*
1547*5331Samw 	 * cleanup if there were any errors that didn't leave
1548*5331Samw 	 * these values where they would be cleaned up later.
1549*5331Samw 	 */
1550*5331Samw 	if (entry != NULL)
1551*5331Samw 		scf_entry_destroy(entry);
1552*5331Samw 
1553*5331Samw 	return (ret);
1554*5331Samw }
1555*5331Samw 
1556*5331Samw /*
15573034Sdougm  * sa_commit_share(handle, group, share)
15583034Sdougm  *
15594653Sdougm  *	Commit this share to the repository.
15603034Sdougm  *	properties are added if they exist but can be added later.
15613034Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
15623034Sdougm  */
15633034Sdougm int
15643034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
15653034Sdougm {
15663034Sdougm 	int ret = SA_OK;
15673034Sdougm 	char *groupname;
15683034Sdougm 	char *name;
15693034Sdougm 	char *description;
15703034Sdougm 	char *sharename;
15713034Sdougm 	ssize_t proplen;
15723034Sdougm 	char *propstring;
15733034Sdougm 
15743034Sdougm 	/*
15754653Sdougm 	 * Don't commit in the zfs group. We do commit legacy
15763034Sdougm 	 * (default) and all other groups/shares. ZFS is handled
15773034Sdougm 	 * through the ZFS configuration rather than SMF.
15783034Sdougm 	 */
15793034Sdougm 
15803034Sdougm 	groupname = sa_get_group_attr(group, "name");
15813034Sdougm 	if (groupname != NULL) {
15824653Sdougm 		if (strcmp(groupname, "zfs") == 0) {
15834653Sdougm 			/*
15844653Sdougm 			 * Adding to the ZFS group will result in the sharenfs
15854653Sdougm 			 * property being set but we don't want to do anything
15864653Sdougm 			 * SMF related at this point.
15874653Sdougm 			 */
15884653Sdougm 			sa_free_attr_string(groupname);
15894653Sdougm 			return (ret);
15904653Sdougm 		}
15913034Sdougm 	}
15923034Sdougm 
15933034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
15943034Sdougm 	propstring = malloc(proplen);
15953034Sdougm 	if (propstring == NULL)
15964653Sdougm 		ret = SA_NO_MEMORY;
15973034Sdougm 
15983034Sdougm 	if (groupname != NULL && ret == SA_OK) {
15994653Sdougm 		ret = sa_get_instance(handle, groupname);
16004653Sdougm 		sa_free_attr_string(groupname);
16014653Sdougm 		groupname = NULL;
16024653Sdougm 		sharename = sa_get_share_attr(share, "id");
16034653Sdougm 		if (sharename == NULL) {
16044653Sdougm 			/* slipped by */
16054653Sdougm 			char shname[SA_SHARE_UUID_BUFLEN];
16064653Sdougm 			generate_unique_sharename(shname);
16074653Sdougm 			xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
16083034Sdougm 			    (xmlChar *)shname);
16094653Sdougm 			sharename = strdup(shname);
16103034Sdougm 		}
16114653Sdougm 		if (sharename != NULL) {
16124653Sdougm 			sigset_t old, new;
16134653Sdougm 			/*
16144653Sdougm 			 * Have a share name allocated so create a pgroup for
16154653Sdougm 			 * it. It may already exist, but that is OK.  In order
16164653Sdougm 			 * to avoid creating a share pgroup that doesn't have
16174653Sdougm 			 * a path property, block signals around the critical
16184653Sdougm 			 * region of creating the share pgroup and props.
16194653Sdougm 			 */
16204653Sdougm 			(void) sigprocmask(SIG_BLOCK, NULL, &new);
16214653Sdougm 			(void) sigaddset(&new, SIGHUP);
16224653Sdougm 			(void) sigaddset(&new, SIGINT);
16234653Sdougm 			(void) sigaddset(&new, SIGQUIT);
16244653Sdougm 			(void) sigaddset(&new, SIGTSTP);
16254653Sdougm 			(void) sigprocmask(SIG_SETMASK, &new, &old);
16264653Sdougm 
16274653Sdougm 			ret = sa_create_pgroup(handle, sharename);
16284653Sdougm 			if (ret == SA_OK) {
16294653Sdougm 				/*
16304653Sdougm 				 * Now start the transaction for the
16314653Sdougm 				 * properties that define this share. They may
16324653Sdougm 				 * exist so attempt to update before create.
16334653Sdougm 				 */
16344653Sdougm 				ret = sa_start_transaction(handle, sharename);
16354653Sdougm 			}
16364653Sdougm 			if (ret == SA_OK) {
16374653Sdougm 				name = sa_get_share_attr(share, "path");
16384653Sdougm 				if (name != NULL) {
16394653Sdougm 					/*
16404653Sdougm 					 * There needs to be a path
16414653Sdougm 					 * for a share to exist.
16424653Sdougm 					 */
16434653Sdougm 					ret = sa_set_property(handle, "path",
16444653Sdougm 					    name);
16454653Sdougm 					sa_free_attr_string(name);
16464653Sdougm 				} else {
16474653Sdougm 					ret = SA_NO_MEMORY;
16484653Sdougm 				}
16494653Sdougm 			}
16504653Sdougm 			if (ret == SA_OK) {
1651*5331Samw 				name = sa_get_share_attr(share, "drive-letter");
1652*5331Samw 				if (name != NULL) {
1653*5331Samw 					/* A drive letter may exist for SMB */
16544653Sdougm 					ret = sa_set_property(handle,
1655*5331Samw 					    "drive-letter", name);
1656*5331Samw 					sa_free_attr_string(name);
16574653Sdougm 				}
16584653Sdougm 			}
16594653Sdougm 			if (ret == SA_OK) {
1660*5331Samw 				name = sa_get_share_attr(share, "exclude");
1661*5331Samw 				if (name != NULL) {
1662*5331Samw 					/*
1663*5331Samw 					 * In special cases need to
1664*5331Samw 					 * exclude proto enable.
1665*5331Samw 					 */
1666*5331Samw 					ret = sa_set_property(handle,
1667*5331Samw 					    "exclude", name);
1668*5331Samw 					sa_free_attr_string(name);
1669*5331Samw 				}
1670*5331Samw 			}
1671*5331Samw 			if (ret == SA_OK) {
1672*5331Samw 				/*
1673*5331Samw 				 * If there are resource names, bundle them up
1674*5331Samw 				 * and save appropriately.
1675*5331Samw 				 */
1676*5331Samw 				ret = sa_set_resource_property(handle, share);
1677*5331Samw 			}
1678*5331Samw 
1679*5331Samw 			if (ret == SA_OK) {
16804653Sdougm 				description = sa_get_share_description(share);
16814653Sdougm 				if (description != NULL) {
16824653Sdougm 					ret = sa_set_property(handle,
16834653Sdougm 					    "description",
16844653Sdougm 					    description);
16854653Sdougm 					sa_free_share_description(description);
16864653Sdougm 				}
16874653Sdougm 			}
16884653Sdougm 			/* Make sure we cleanup the transaction */
16894653Sdougm 			if (ret == SA_OK) {
16904653Sdougm 				ret = sa_end_transaction(handle);
16914653Sdougm 			} else {
16924653Sdougm 				sa_abort_transaction(handle);
16934653Sdougm 			}
16944653Sdougm 
16954653Sdougm 			(void) sigprocmask(SIG_SETMASK, &old, NULL);
16964653Sdougm 
16974653Sdougm 			free(sharename);
16983034Sdougm 		}
16993034Sdougm 	}
17003034Sdougm 	if (ret == SA_SYSTEM_ERR) {
17014653Sdougm 		int err = scf_error();
17024653Sdougm 		if (err == SCF_ERROR_PERMISSION_DENIED)
17034653Sdougm 			ret = SA_NO_PERMISSION;
17043034Sdougm 	}
17053034Sdougm 	if (propstring != NULL)
17064653Sdougm 		free(propstring);
17073034Sdougm 	if (groupname != NULL)
17084653Sdougm 		sa_free_attr_string(groupname);
17093034Sdougm 
17103034Sdougm 	return (ret);
17113034Sdougm }
17123034Sdougm 
17133034Sdougm /*
1714*5331Samw  * remove_resources(handle, share, shareid)
1715*5331Samw  *
1716*5331Samw  * If the share has resources, remove all of them and their
1717*5331Samw  * optionsets.
1718*5331Samw  */
1719*5331Samw static int
1720*5331Samw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
1721*5331Samw {
1722*5331Samw 	sa_resource_t resource;
1723*5331Samw 	sa_optionset_t opt;
1724*5331Samw 	char *proto;
1725*5331Samw 	char *id;
1726*5331Samw 	ssize_t proplen;
1727*5331Samw 	char *propstring;
1728*5331Samw 	int ret = SA_OK;
1729*5331Samw 
1730*5331Samw 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1731*5331Samw 	propstring = malloc(proplen);
1732*5331Samw 	if (propstring == NULL)
1733*5331Samw 		return (SA_NO_MEMORY);
1734*5331Samw 
1735*5331Samw 	for (resource = sa_get_share_resource(share, NULL);
1736*5331Samw 	    resource != NULL; resource = sa_get_next_resource(resource)) {
1737*5331Samw 		id = sa_get_resource_attr(resource, "id");
1738*5331Samw 		if (id == NULL)
1739*5331Samw 			continue;
1740*5331Samw 		for (opt = sa_get_optionset(resource, NULL);
1741*5331Samw 		    opt != NULL; opt = sa_get_next_optionset(resource)) {
1742*5331Samw 			proto = sa_get_optionset_attr(opt, "type");
1743*5331Samw 			if (proto != NULL) {
1744*5331Samw 				(void) snprintf(propstring, proplen,
1745*5331Samw 				    "%s_%s_%s", shareid, proto, id);
1746*5331Samw 				ret = sa_delete_pgroup(handle, propstring);
1747*5331Samw 				sa_free_attr_string(proto);
1748*5331Samw 			}
1749*5331Samw 		}
1750*5331Samw 		sa_free_attr_string(id);
1751*5331Samw 	}
1752*5331Samw 	free(propstring);
1753*5331Samw 	return (ret);
1754*5331Samw }
1755*5331Samw 
1756*5331Samw /*
17573034Sdougm  * sa_delete_share(handle, group, share)
17583034Sdougm  *
17594653Sdougm  * Remove the specified share from the group (and service instance).
17603034Sdougm  */
17613034Sdougm 
17623034Sdougm int
17633034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
17643034Sdougm {
17653034Sdougm 	int ret = SA_OK;
17663034Sdougm 	char *groupname = NULL;
17673034Sdougm 	char *shareid = NULL;
17683034Sdougm 	sa_optionset_t opt;
17693034Sdougm 	sa_security_t sec;
17703034Sdougm 	ssize_t proplen;
17713034Sdougm 	char *propstring;
17723034Sdougm 
17733034Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
17743034Sdougm 	propstring = malloc(proplen);
17753034Sdougm 	if (propstring == NULL)
17764653Sdougm 		ret = SA_NO_MEMORY;
17773034Sdougm 
17783034Sdougm 	if (ret == SA_OK) {
17794653Sdougm 		groupname = sa_get_group_attr(group, "name");
17804653Sdougm 		shareid = sa_get_share_attr(share, "id");
17814653Sdougm 		if (groupname == NULL || shareid == NULL) {
17824653Sdougm 			ret = SA_CONFIG_ERR;
17834653Sdougm 			goto out;
17844653Sdougm 		}
17853034Sdougm 		ret = sa_get_instance(handle, groupname);
17863034Sdougm 		if (ret == SA_OK) {
1787*5331Samw 			/* If a share has resources, remove them */
1788*5331Samw 			ret = remove_resources(handle, share, shareid);
17894653Sdougm 			/* If a share has properties, remove them */
17904653Sdougm 			ret = sa_delete_pgroup(handle, shareid);
17914653Sdougm 			for (opt = sa_get_optionset(share, NULL);
17924653Sdougm 			    opt != NULL;
17934653Sdougm 			    opt = sa_get_next_optionset(opt)) {
17944653Sdougm 				char *proto;
17954653Sdougm 				proto = sa_get_optionset_attr(opt, "type");
17964653Sdougm 				if (proto != NULL) {
17974653Sdougm 					(void) snprintf(propstring,
17984653Sdougm 					    proplen, "%s_%s", shareid,
17994653Sdougm 					    proto);
18004653Sdougm 					ret = sa_delete_pgroup(handle,
18014653Sdougm 					    propstring);
18024653Sdougm 					sa_free_attr_string(proto);
18034653Sdougm 				} else {
18044653Sdougm 					ret = SA_NO_MEMORY;
18054653Sdougm 				}
18063034Sdougm 			}
18073034Sdougm 			/*
18084653Sdougm 			 * If a share has security/negotiable
18093034Sdougm 			 * properties, remove them.
18103034Sdougm 			 */
18114653Sdougm 			for (sec = sa_get_security(share, NULL, NULL);
18124653Sdougm 			    sec != NULL;
18134653Sdougm 			    sec = sa_get_next_security(sec)) {
18144653Sdougm 				char *proto;
18154653Sdougm 				char *sectype;
18164653Sdougm 				proto = sa_get_security_attr(sec, "type");
18174653Sdougm 				sectype = sa_get_security_attr(sec, "sectype");
18184653Sdougm 				if (proto != NULL && sectype != NULL) {
18194653Sdougm 					(void) snprintf(propstring, proplen,
18204653Sdougm 					    "%s_%s_%s", shareid,  proto,
18214653Sdougm 					    sectype);
18224653Sdougm 					ret = sa_delete_pgroup(handle,
18234653Sdougm 					    propstring);
18244653Sdougm 				} else {
18254653Sdougm 					ret = SA_NO_MEMORY;
18264653Sdougm 				}
18274653Sdougm 				if (proto != NULL)
18284653Sdougm 					sa_free_attr_string(proto);
18294653Sdougm 				if (sectype != NULL)
18304653Sdougm 					sa_free_attr_string(sectype);
18313034Sdougm 			}
18323034Sdougm 		}
18333034Sdougm 	}
18344653Sdougm out:
18353034Sdougm 	if (groupname != NULL)
18364653Sdougm 		sa_free_attr_string(groupname);
18373034Sdougm 	if (shareid != NULL)
18384653Sdougm 		sa_free_attr_string(shareid);
18393034Sdougm 	if (propstring != NULL)
18404653Sdougm 		free(propstring);
18413034Sdougm 
18423034Sdougm 	return (ret);
18433034Sdougm }
1844