xref: /titanic_44/usr/src/lib/libshare/common/scfutil.c (revision 6185db853e024a486ff8837e6784dd290d866112)
1*6185db85Sdougm /*
2*6185db85Sdougm  * CDDL HEADER START
3*6185db85Sdougm  *
4*6185db85Sdougm  * The contents of this file are subject to the terms of the
5*6185db85Sdougm  * Common Development and Distribution License (the "License").
6*6185db85Sdougm  * You may not use this file except in compliance with the License.
7*6185db85Sdougm  *
8*6185db85Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6185db85Sdougm  * or http://www.opensolaris.org/os/licensing.
10*6185db85Sdougm  * See the License for the specific language governing permissions
11*6185db85Sdougm  * and limitations under the License.
12*6185db85Sdougm  *
13*6185db85Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
14*6185db85Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6185db85Sdougm  * If applicable, add the following below this CDDL HEADER, with the
16*6185db85Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
17*6185db85Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6185db85Sdougm  *
19*6185db85Sdougm  * CDDL HEADER END
20*6185db85Sdougm  */
21*6185db85Sdougm 
22*6185db85Sdougm /*
23*6185db85Sdougm  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*6185db85Sdougm  * Use is subject to license terms.
25*6185db85Sdougm  */
26*6185db85Sdougm 
27*6185db85Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*6185db85Sdougm 
29*6185db85Sdougm /* helper functions for using libscf with sharemgr */
30*6185db85Sdougm 
31*6185db85Sdougm #include <libscf.h>
32*6185db85Sdougm #include <libxml/parser.h>
33*6185db85Sdougm #include <libxml/tree.h>
34*6185db85Sdougm #include "libshare.h"
35*6185db85Sdougm #include "libshare_impl.h"
36*6185db85Sdougm #include "scfutil.h"
37*6185db85Sdougm #include <string.h>
38*6185db85Sdougm #include <errno.h>
39*6185db85Sdougm #include <uuid/uuid.h>
40*6185db85Sdougm #include <sys/param.h>
41*6185db85Sdougm 
42*6185db85Sdougm ssize_t scf_max_name_len;
43*6185db85Sdougm extern struct sa_proto_plugin *sap_proto_list;
44*6185db85Sdougm 
45*6185db85Sdougm /*
46*6185db85Sdougm  * The SMF facility uses some properties that must exist. We want to
47*6185db85Sdougm  * skip over these when processing protocol options.
48*6185db85Sdougm  */
49*6185db85Sdougm static char *skip_props[] = {
50*6185db85Sdougm 	"modify_authorization",
51*6185db85Sdougm 	"action_authorization",
52*6185db85Sdougm 	"value_authorization",
53*6185db85Sdougm 	NULL
54*6185db85Sdougm };
55*6185db85Sdougm 
56*6185db85Sdougm /*
57*6185db85Sdougm  * sa_scf_fini(handle)
58*6185db85Sdougm  *
59*6185db85Sdougm  * must be called when done. Called with the handle allocated in
60*6185db85Sdougm  * sa_scf_init(), it cleans up the state and frees any SCF resources
61*6185db85Sdougm  * still in use. Called by sa_fini().
62*6185db85Sdougm  */
63*6185db85Sdougm 
64*6185db85Sdougm void
65*6185db85Sdougm sa_scf_fini(scfutilhandle_t *handle)
66*6185db85Sdougm {
67*6185db85Sdougm 	if (handle != NULL) {
68*6185db85Sdougm 	    int unbind = 0;
69*6185db85Sdougm 	    if (handle->scope != NULL) {
70*6185db85Sdougm 		unbind = 1;
71*6185db85Sdougm 		scf_scope_destroy(handle->scope);
72*6185db85Sdougm 	    }
73*6185db85Sdougm 	    if (handle->service != NULL)
74*6185db85Sdougm 		    scf_service_destroy(handle->service);
75*6185db85Sdougm 	    if (handle->pg != NULL)
76*6185db85Sdougm 		scf_pg_destroy(handle->pg);
77*6185db85Sdougm 	    if (handle->handle != NULL) {
78*6185db85Sdougm 		handle->scf_state = SCH_STATE_UNINIT;
79*6185db85Sdougm 		if (unbind)
80*6185db85Sdougm 		    (void) scf_handle_unbind(handle->handle);
81*6185db85Sdougm 		scf_handle_destroy(handle->handle);
82*6185db85Sdougm 	    }
83*6185db85Sdougm 	    free(handle);
84*6185db85Sdougm 	}
85*6185db85Sdougm }
86*6185db85Sdougm 
87*6185db85Sdougm /*
88*6185db85Sdougm  * sa_scf_init()
89*6185db85Sdougm  *
90*6185db85Sdougm  * must be called before using any of the SCF functions. Called by
91*6185db85Sdougm  * sa_init() during the API setup.
92*6185db85Sdougm  */
93*6185db85Sdougm 
94*6185db85Sdougm scfutilhandle_t *
95*6185db85Sdougm sa_scf_init()
96*6185db85Sdougm {
97*6185db85Sdougm 	scfutilhandle_t *handle;
98*6185db85Sdougm 
99*6185db85Sdougm 	scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
100*6185db85Sdougm 	if (scf_max_name_len <= 0)
101*6185db85Sdougm 	    scf_max_name_len = SA_MAX_NAME_LEN + 1;
102*6185db85Sdougm 
103*6185db85Sdougm 	handle = calloc(1, sizeof (scfutilhandle_t));
104*6185db85Sdougm 	if (handle != NULL) {
105*6185db85Sdougm 	    handle->scf_state = SCH_STATE_INITIALIZING;
106*6185db85Sdougm 	    handle->handle = scf_handle_create(SCF_VERSION);
107*6185db85Sdougm 	    if (handle->handle != NULL) {
108*6185db85Sdougm 		if (scf_handle_bind(handle->handle) == 0) {
109*6185db85Sdougm 		    handle->scope = scf_scope_create(handle->handle);
110*6185db85Sdougm 		    handle->service = scf_service_create(handle->handle);
111*6185db85Sdougm 		    handle->pg = scf_pg_create(handle->handle);
112*6185db85Sdougm 		    handle->instance = scf_instance_create(handle->handle);
113*6185db85Sdougm 		    if (scf_handle_get_scope(handle->handle,
114*6185db85Sdougm 					SCF_SCOPE_LOCAL, handle->scope) == 0) {
115*6185db85Sdougm 			if (scf_scope_get_service(handle->scope,
116*6185db85Sdougm 						    SA_GROUP_SVC_NAME,
117*6185db85Sdougm 						    handle->service) != 0) {
118*6185db85Sdougm 			    goto err;
119*6185db85Sdougm 			}
120*6185db85Sdougm 			handle->scf_state = SCH_STATE_INIT;
121*6185db85Sdougm 			if (sa_get_instance(handle, "default") != SA_OK) {
122*6185db85Sdougm 			    char **protolist;
123*6185db85Sdougm 			    int numprotos, i;
124*6185db85Sdougm 			    sa_group_t defgrp;
125*6185db85Sdougm 			    defgrp = sa_create_group("default", NULL);
126*6185db85Sdougm 			    if (defgrp != NULL) {
127*6185db85Sdougm 				numprotos = sa_get_protocols(&protolist);
128*6185db85Sdougm 				for (i = 0; i < numprotos; i++) {
129*6185db85Sdougm 				    (void) sa_create_optionset(defgrp,
130*6185db85Sdougm 								protolist[i]);
131*6185db85Sdougm 				}
132*6185db85Sdougm 				if (protolist != NULL)
133*6185db85Sdougm 				    free(protolist);
134*6185db85Sdougm 			    }
135*6185db85Sdougm 			}
136*6185db85Sdougm 		    } else {
137*6185db85Sdougm 			goto err;
138*6185db85Sdougm 		    }
139*6185db85Sdougm 		} else {
140*6185db85Sdougm 		    goto err;
141*6185db85Sdougm 		}
142*6185db85Sdougm 	    } else {
143*6185db85Sdougm 		free(handle);
144*6185db85Sdougm 		handle = NULL;
145*6185db85Sdougm 		(void) printf("libshare could not access SMF repository: %s\n",
146*6185db85Sdougm 				scf_strerror(scf_error()));
147*6185db85Sdougm 	    }
148*6185db85Sdougm 	}
149*6185db85Sdougm 	return (handle);
150*6185db85Sdougm 
151*6185db85Sdougm 	/* error handling/unwinding */
152*6185db85Sdougm err:
153*6185db85Sdougm 	(void) sa_scf_fini(handle);
154*6185db85Sdougm 	(void) printf("libshare SMF initialization problem: %s\n",
155*6185db85Sdougm 			scf_strerror(scf_error()));
156*6185db85Sdougm 	return (NULL);
157*6185db85Sdougm }
158*6185db85Sdougm 
159*6185db85Sdougm /*
160*6185db85Sdougm  * get_scf_limit(name)
161*6185db85Sdougm  *
162*6185db85Sdougm  * Since we use  scf_limit a lot and do the same  check and return the
163*6185db85Sdougm  * same  value  if  it  fails,   implement  as  a  function  for  code
164*6185db85Sdougm  * simplification.  Basically, if  name isn't found, return MAXPATHLEN
165*6185db85Sdougm  * (1024) so we have a reasonable default buffer size.
166*6185db85Sdougm  */
167*6185db85Sdougm static ssize_t
168*6185db85Sdougm get_scf_limit(uint32_t name)
169*6185db85Sdougm {
170*6185db85Sdougm 	ssize_t vallen;
171*6185db85Sdougm 
172*6185db85Sdougm 	vallen = scf_limit(name);
173*6185db85Sdougm 	if (vallen == (ssize_t)-1)
174*6185db85Sdougm 	    vallen = MAXPATHLEN;
175*6185db85Sdougm 	return (vallen);
176*6185db85Sdougm }
177*6185db85Sdougm 
178*6185db85Sdougm /*
179*6185db85Sdougm  * skip_property(name)
180*6185db85Sdougm  *
181*6185db85Sdougm  * internal function to check to see if a property is an SMF magic
182*6185db85Sdougm  * property that needs to be skipped.
183*6185db85Sdougm  */
184*6185db85Sdougm static int
185*6185db85Sdougm skip_property(char *name)
186*6185db85Sdougm {
187*6185db85Sdougm 	int i;
188*6185db85Sdougm 
189*6185db85Sdougm 	for (i = 0; skip_props[i] != NULL; i++)
190*6185db85Sdougm 	    if (strcmp(name, skip_props[i]) == 0)
191*6185db85Sdougm 		return (1);
192*6185db85Sdougm 	return (0);
193*6185db85Sdougm }
194*6185db85Sdougm 
195*6185db85Sdougm /*
196*6185db85Sdougm  * generate_unique_sharename(sharename)
197*6185db85Sdougm  *
198*6185db85Sdougm  * Shares are represented in SMF as property groups. Due to share
199*6185db85Sdougm  * paths containing characters that are not allowed in SMF names and
200*6185db85Sdougm  * the need to be unique, we use UUIDs to construct a unique name.
201*6185db85Sdougm  */
202*6185db85Sdougm 
203*6185db85Sdougm static void
204*6185db85Sdougm generate_unique_sharename(char *sharename)
205*6185db85Sdougm {
206*6185db85Sdougm 	uuid_t uuid;
207*6185db85Sdougm 
208*6185db85Sdougm 	uuid_generate(uuid);
209*6185db85Sdougm 	(void) strcpy(sharename, "S-");
210*6185db85Sdougm 	uuid_unparse(uuid, sharename + 2);
211*6185db85Sdougm }
212*6185db85Sdougm 
213*6185db85Sdougm /*
214*6185db85Sdougm  * valid_protocol(proto)
215*6185db85Sdougm  *
216*6185db85Sdougm  * check to see if the specified protocol is a valid one for the
217*6185db85Sdougm  * general sharemgr facility. We determine this by checking which
218*6185db85Sdougm  * plugin protocols were found.
219*6185db85Sdougm  */
220*6185db85Sdougm 
221*6185db85Sdougm static int
222*6185db85Sdougm valid_protocol(char *proto)
223*6185db85Sdougm {
224*6185db85Sdougm 	struct sa_proto_plugin *plugin;
225*6185db85Sdougm 	for (plugin = sap_proto_list; plugin != NULL;
226*6185db85Sdougm 	    plugin = plugin->plugin_next)
227*6185db85Sdougm 	    if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
228*6185db85Sdougm 		return (1);
229*6185db85Sdougm 	return (0);
230*6185db85Sdougm }
231*6185db85Sdougm 
232*6185db85Sdougm /*
233*6185db85Sdougm  * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
234*6185db85Sdougm  *
235*6185db85Sdougm  * extract the name property group and create the specified type of
236*6185db85Sdougm  * node on the provided group.  type will be optionset or security.
237*6185db85Sdougm  */
238*6185db85Sdougm 
239*6185db85Sdougm static int
240*6185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
241*6185db85Sdougm 			scf_propertygroup_t *pg,
242*6185db85Sdougm 			char *nodetype, char *proto, char *sectype)
243*6185db85Sdougm {
244*6185db85Sdougm 	xmlNodePtr node;
245*6185db85Sdougm 	scf_iter_t *iter;
246*6185db85Sdougm 	scf_property_t *prop;
247*6185db85Sdougm 	scf_value_t *value;
248*6185db85Sdougm 	char *name;
249*6185db85Sdougm 	char *valuestr;
250*6185db85Sdougm 	ssize_t vallen;
251*6185db85Sdougm 	int ret = SA_OK;
252*6185db85Sdougm 
253*6185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
254*6185db85Sdougm 
255*6185db85Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
256*6185db85Sdougm 	if (node != NULL) {
257*6185db85Sdougm 	    if (proto != NULL)
258*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
259*6185db85Sdougm 	    if (sectype != NULL)
260*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
261*6185db85Sdougm 		/*
262*6185db85Sdougm 		 * have node to work with so iterate over the properties
263*6185db85Sdougm 		 * in the pg and create option sub nodes.
264*6185db85Sdougm 		 */
265*6185db85Sdougm 		iter = scf_iter_create(handle->handle);
266*6185db85Sdougm 		value = scf_value_create(handle->handle);
267*6185db85Sdougm 		prop = scf_property_create(handle->handle);
268*6185db85Sdougm 		name = malloc(scf_max_name_len);
269*6185db85Sdougm 		valuestr = malloc(vallen);
270*6185db85Sdougm 		/*
271*6185db85Sdougm 		 * want to iterate through the properties and add them
272*6185db85Sdougm 		 * to the base optionset.
273*6185db85Sdougm 		 */
274*6185db85Sdougm 		if (iter != NULL && value != NULL && prop != NULL &&
275*6185db85Sdougm 		    valuestr != NULL && name != NULL) {
276*6185db85Sdougm 		    if (scf_iter_pg_properties(iter, pg) == 0) {
277*6185db85Sdougm 			/* now iterate the properties in the group */
278*6185db85Sdougm 			while (scf_iter_next_property(iter, prop) > 0) {
279*6185db85Sdougm 			    /* have a property */
280*6185db85Sdougm 			    if (scf_property_get_name(prop, name,
281*6185db85Sdougm 							scf_max_name_len) > 0) {
282*6185db85Sdougm 				/* some properties are part of the framework */
283*6185db85Sdougm 				if (skip_property(name))
284*6185db85Sdougm 				    continue;
285*6185db85Sdougm 				if (scf_property_get_value(prop, value) == 0) {
286*6185db85Sdougm 				    if (scf_value_get_astring(value, valuestr,
287*6185db85Sdougm 								vallen) >= 0) {
288*6185db85Sdougm 					sa_property_t saprop;
289*6185db85Sdougm 					saprop = sa_create_property(name,
290*6185db85Sdougm 								    valuestr);
291*6185db85Sdougm 					if (saprop != NULL) {
292*6185db85Sdougm 					/*
293*6185db85Sdougm 					 * since in SMF, don't
294*6185db85Sdougm 					 * recurse. Use xmlAddChild
295*6185db85Sdougm 					 * directly, instead.
296*6185db85Sdougm 					 */
297*6185db85Sdougm 					    xmlAddChild(node,
298*6185db85Sdougm 							(xmlNodePtr) saprop);
299*6185db85Sdougm 					}
300*6185db85Sdougm 				    }
301*6185db85Sdougm 				}
302*6185db85Sdougm 			    }
303*6185db85Sdougm 			}
304*6185db85Sdougm 		    }
305*6185db85Sdougm 		} else {
306*6185db85Sdougm 		    ret = SA_NO_MEMORY;
307*6185db85Sdougm 		}
308*6185db85Sdougm 		/* cleanup to avoid memory leaks */
309*6185db85Sdougm 		if (value != NULL)
310*6185db85Sdougm 		    scf_value_destroy(value);
311*6185db85Sdougm 		if (iter != NULL)
312*6185db85Sdougm 		    scf_iter_destroy(iter);
313*6185db85Sdougm 		if (prop != NULL)
314*6185db85Sdougm 		    scf_property_destroy(prop);
315*6185db85Sdougm 		if (name != NULL)
316*6185db85Sdougm 		    free(name);
317*6185db85Sdougm 		if (valuestr != NULL)
318*6185db85Sdougm 		    free(valuestr);
319*6185db85Sdougm 	}
320*6185db85Sdougm 	return (ret);
321*6185db85Sdougm }
322*6185db85Sdougm 
323*6185db85Sdougm /*
324*6185db85Sdougm  * sa_extract_attrs(root, handle, instance)
325*6185db85Sdougm  *
326*6185db85Sdougm  * local function to extract the actual attributes/properties from the
327*6185db85Sdougm  * property group of the service instance. These are the well known
328*6185db85Sdougm  * attributes of "state" and "zfs". If additional attributes are
329*6185db85Sdougm  * added, they should be added here.
330*6185db85Sdougm  */
331*6185db85Sdougm 
332*6185db85Sdougm static void
333*6185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
334*6185db85Sdougm 		    scf_instance_t *instance)
335*6185db85Sdougm {
336*6185db85Sdougm 	scf_property_t *prop;
337*6185db85Sdougm 	scf_value_t *value;
338*6185db85Sdougm 	char *valuestr;
339*6185db85Sdougm 	ssize_t vallen;
340*6185db85Sdougm 
341*6185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
342*6185db85Sdougm 	prop = scf_property_create(handle->handle);
343*6185db85Sdougm 	value = scf_value_create(handle->handle);
344*6185db85Sdougm 	valuestr = malloc(vallen);
345*6185db85Sdougm 	if (prop != NULL && value != NULL && valuestr != NULL &&
346*6185db85Sdougm 	    scf_instance_get_pg(instance, "operation",
347*6185db85Sdougm 				handle->pg) == 0) {
348*6185db85Sdougm 		/*
349*6185db85Sdougm 		 * have a property group with desired name so now get
350*6185db85Sdougm 		 * the known attributes.
351*6185db85Sdougm 		 */
352*6185db85Sdougm 	    if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
353*6185db85Sdougm 		/* found the property so get the value */
354*6185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
355*6185db85Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) >= 0) {
356*6185db85Sdougm 			xmlSetProp(root, (xmlChar *)"state",
357*6185db85Sdougm 				    (xmlChar *)valuestr);
358*6185db85Sdougm 		    }
359*6185db85Sdougm 		}
360*6185db85Sdougm 	    }
361*6185db85Sdougm 	    if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
362*6185db85Sdougm 		/* found the property so get the value */
363*6185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
364*6185db85Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) > 0) {
365*6185db85Sdougm 			xmlSetProp(root, (xmlChar *)"zfs",
366*6185db85Sdougm 				    (xmlChar *)valuestr);
367*6185db85Sdougm 		    }
368*6185db85Sdougm 		}
369*6185db85Sdougm 	    }
370*6185db85Sdougm 	}
371*6185db85Sdougm 	if (valuestr != NULL)
372*6185db85Sdougm 	    free(valuestr);
373*6185db85Sdougm 	if (value != NULL)
374*6185db85Sdougm 	    scf_value_destroy(value);
375*6185db85Sdougm 	if (prop != NULL)
376*6185db85Sdougm 	    scf_property_destroy(prop);
377*6185db85Sdougm }
378*6185db85Sdougm 
379*6185db85Sdougm /*
380*6185db85Sdougm  * list of known share attributes.
381*6185db85Sdougm  */
382*6185db85Sdougm 
383*6185db85Sdougm static char *share_attr[] = {
384*6185db85Sdougm 	"path",
385*6185db85Sdougm 	"id",
386*6185db85Sdougm 	"resource",
387*6185db85Sdougm 	NULL,
388*6185db85Sdougm };
389*6185db85Sdougm 
390*6185db85Sdougm static int
391*6185db85Sdougm is_share_attr(char *name)
392*6185db85Sdougm {
393*6185db85Sdougm 	int i;
394*6185db85Sdougm 	for (i = 0; share_attr[i] != NULL; i++)
395*6185db85Sdougm 	    if (strcmp(name, share_attr[i]) == 0)
396*6185db85Sdougm 		return (1);
397*6185db85Sdougm 	return (0);
398*6185db85Sdougm }
399*6185db85Sdougm 
400*6185db85Sdougm /*
401*6185db85Sdougm  * sa_share_from_pgroup
402*6185db85Sdougm  *
403*6185db85Sdougm  * extract the share definition from the share property group. We do
404*6185db85Sdougm  * some sanity checking to avoid bad data.
405*6185db85Sdougm  *
406*6185db85Sdougm  * Since this is only constructing the internal data structures, we
407*6185db85Sdougm  * don't use the sa_* functions most of the time.
408*6185db85Sdougm  */
409*6185db85Sdougm void
410*6185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
411*6185db85Sdougm 			scf_propertygroup_t *pg, char *id)
412*6185db85Sdougm {
413*6185db85Sdougm 	xmlNodePtr node;
414*6185db85Sdougm 	char *name;
415*6185db85Sdougm 	scf_iter_t *iter;
416*6185db85Sdougm 	scf_property_t *prop;
417*6185db85Sdougm 	scf_value_t *value;
418*6185db85Sdougm 	ssize_t vallen;
419*6185db85Sdougm 	char *valuestr;
420*6185db85Sdougm 	int ret = SA_OK;
421*6185db85Sdougm 
422*6185db85Sdougm 	/*
423*6185db85Sdougm 	 * While preliminary check (starts with 'S') passed before
424*6185db85Sdougm 	 * getting here. Need to make sure it is in ID syntax
425*6185db85Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
426*6185db85Sdougm 	 * pgroups.
427*6185db85Sdougm 	 */
428*6185db85Sdougm 	vallen = strlen(id);
429*6185db85Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
430*6185db85Sdougm 	    uuid_t uuid;
431*6185db85Sdougm 	    if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 ||
432*6185db85Sdougm 		uuid_parse(id + 2, uuid) < 0)
433*6185db85Sdougm 		return;
434*6185db85Sdougm 	} else {
435*6185db85Sdougm 	    return;
436*6185db85Sdougm 	}
437*6185db85Sdougm 
438*6185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
439*6185db85Sdougm 
440*6185db85Sdougm 	iter = scf_iter_create(handle->handle);
441*6185db85Sdougm 	value = scf_value_create(handle->handle);
442*6185db85Sdougm 	prop = scf_property_create(handle->handle);
443*6185db85Sdougm 	name = malloc(scf_max_name_len);
444*6185db85Sdougm 	valuestr = malloc(vallen);
445*6185db85Sdougm 
446*6185db85Sdougm 	/*
447*6185db85Sdougm 	 * construct the share XML node. It is similar to sa_add_share
448*6185db85Sdougm 	 * but never changes the repository. Also, there won't be any
449*6185db85Sdougm 	 * ZFS or transient shares.  Root will be the group it is
450*6185db85Sdougm 	 * associated with.
451*6185db85Sdougm 	 */
452*6185db85Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
453*6185db85Sdougm 	if (node != NULL) {
454*6185db85Sdougm 		/*
455*6185db85Sdougm 		 * make sure the UUID part of the property group is
456*6185db85Sdougm 		 * stored in the share "id" property. We use this
457*6185db85Sdougm 		 * later.
458*6185db85Sdougm 		 */
459*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
460*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist");
461*6185db85Sdougm 	}
462*6185db85Sdougm 
463*6185db85Sdougm 	if (iter != NULL && value != NULL && prop != NULL && name != NULL) {
464*6185db85Sdougm 		/* iterate over the share pg properties */
465*6185db85Sdougm 	    if (scf_iter_pg_properties(iter, pg) == 0) {
466*6185db85Sdougm 		while (scf_iter_next_property(iter, prop) > 0) {
467*6185db85Sdougm 		    ret = SA_SYSTEM_ERR; /* assume the worst */
468*6185db85Sdougm 		    if (scf_property_get_name(prop, name,
469*6185db85Sdougm 						scf_max_name_len) > 0) {
470*6185db85Sdougm 			if (scf_property_get_value(prop, value) == 0) {
471*6185db85Sdougm 			    if (scf_value_get_astring(value, valuestr,
472*6185db85Sdougm 							vallen) >= 0) {
473*6185db85Sdougm 				ret = SA_OK;
474*6185db85Sdougm 			    }
475*6185db85Sdougm 			}
476*6185db85Sdougm 		    }
477*6185db85Sdougm 		    if (ret == SA_OK) {
478*6185db85Sdougm 			if (is_share_attr(name)) {
479*6185db85Sdougm 				/*
480*6185db85Sdougm 				 * if a share attr, then simple -
481*6185db85Sdougm 				 * usually path and resource name
482*6185db85Sdougm 				 */
483*6185db85Sdougm 			    xmlSetProp(node, (xmlChar *)name,
484*6185db85Sdougm 					(xmlChar *)valuestr);
485*6185db85Sdougm 			} else {
486*6185db85Sdougm 			    if (strcmp(name, "description") == 0) {
487*6185db85Sdougm 				/* we have a description node */
488*6185db85Sdougm 				xmlNodePtr desc;
489*6185db85Sdougm 				desc = xmlNewChild(node, NULL,
490*6185db85Sdougm 						    (xmlChar *)"description",
491*6185db85Sdougm 						    NULL);
492*6185db85Sdougm 				if (desc != NULL)
493*6185db85Sdougm 				    xmlNodeSetContent(desc,
494*6185db85Sdougm 							(xmlChar *)valuestr);
495*6185db85Sdougm 			    }
496*6185db85Sdougm 			}
497*6185db85Sdougm 		    }
498*6185db85Sdougm 		}
499*6185db85Sdougm 	    }
500*6185db85Sdougm 	}
501*6185db85Sdougm 	if (name != NULL)
502*6185db85Sdougm 	    free(name);
503*6185db85Sdougm 	if (valuestr != NULL)
504*6185db85Sdougm 	    free(valuestr);
505*6185db85Sdougm 	if (value != NULL)
506*6185db85Sdougm 	    scf_value_destroy(value);
507*6185db85Sdougm 	if (iter != NULL)
508*6185db85Sdougm 	    scf_iter_destroy(iter);
509*6185db85Sdougm 	if (prop != NULL)
510*6185db85Sdougm 	    scf_property_destroy(prop);
511*6185db85Sdougm }
512*6185db85Sdougm 
513*6185db85Sdougm /*
514*6185db85Sdougm  * find_share_by_id(shareid)
515*6185db85Sdougm  *
516*6185db85Sdougm  * Search all shares in all groups until we find the share represented
517*6185db85Sdougm  * by "id".
518*6185db85Sdougm  */
519*6185db85Sdougm 
520*6185db85Sdougm static sa_share_t
521*6185db85Sdougm find_share_by_id(char *shareid)
522*6185db85Sdougm {
523*6185db85Sdougm 	sa_group_t group;
524*6185db85Sdougm 	sa_share_t share = NULL;
525*6185db85Sdougm 	char *id = NULL;
526*6185db85Sdougm 	int done = 0;
527*6185db85Sdougm 
528*6185db85Sdougm 	for (group = sa_get_group(NULL); group != NULL && !done;
529*6185db85Sdougm 		group = sa_get_next_group(group)) {
530*6185db85Sdougm 		for (share = sa_get_share(group, NULL); share != NULL;
531*6185db85Sdougm 			share = sa_get_next_share(share)) {
532*6185db85Sdougm 			id = sa_get_share_attr(share, "id");
533*6185db85Sdougm 			if (id != NULL && strcmp(id, shareid) == 0) {
534*6185db85Sdougm 				sa_free_attr_string(id);
535*6185db85Sdougm 				id = NULL;
536*6185db85Sdougm 				done++;
537*6185db85Sdougm 				break;
538*6185db85Sdougm 			}
539*6185db85Sdougm 			if (id != NULL) {
540*6185db85Sdougm 			    sa_free_attr_string(id);
541*6185db85Sdougm 			    id = NULL;
542*6185db85Sdougm 			}
543*6185db85Sdougm 		}
544*6185db85Sdougm 	}
545*6185db85Sdougm 	return (share);
546*6185db85Sdougm }
547*6185db85Sdougm 
548*6185db85Sdougm /*
549*6185db85Sdougm  * sa_share_props_from_pgroup(root, handle, pg, id)
550*6185db85Sdougm  *
551*6185db85Sdougm  * extract share properties from the SMF property group. More sanity
552*6185db85Sdougm  * checks are done and the share object is created. We ignore some
553*6185db85Sdougm  * errors that could exist in the repository and only worry about
554*6185db85Sdougm  * property groups that validate in naming.
555*6185db85Sdougm  */
556*6185db85Sdougm 
557*6185db85Sdougm static int
558*6185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
559*6185db85Sdougm 			scf_propertygroup_t *pg, char *id)
560*6185db85Sdougm {
561*6185db85Sdougm 	xmlNodePtr node;
562*6185db85Sdougm 	char *name;
563*6185db85Sdougm 	scf_iter_t *iter;
564*6185db85Sdougm 	scf_property_t *prop;
565*6185db85Sdougm 	scf_value_t *value;
566*6185db85Sdougm 	ssize_t vallen;
567*6185db85Sdougm 	char *valuestr;
568*6185db85Sdougm 	int ret = SA_OK;
569*6185db85Sdougm 	char *sectype = NULL;
570*6185db85Sdougm 	char *proto;
571*6185db85Sdougm 	sa_share_t share;
572*6185db85Sdougm 
573*6185db85Sdougm 	/*
574*6185db85Sdougm 	 * While preliminary check (starts with 'S') passed before
575*6185db85Sdougm 	 * getting here. Need to make sure it is in ID syntax
576*6185db85Sdougm 	 * (Snnnnnn). Note that shares with properties have similar
577*6185db85Sdougm 	 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
578*6185db85Sdougm 	 * characters, it is likely one of the protocol/security
579*6185db85Sdougm 	 * versions.
580*6185db85Sdougm 	 */
581*6185db85Sdougm 	vallen = strlen(id);
582*6185db85Sdougm 	if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) {
583*6185db85Sdougm 	    uuid_t uuid;
584*6185db85Sdougm 	    if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
585*6185db85Sdougm 		proto = strchr(id, '_');
586*6185db85Sdougm 		if (proto == NULL)
587*6185db85Sdougm 		    return (ret);
588*6185db85Sdougm 		*proto++ = '\0';
589*6185db85Sdougm 		if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
590*6185db85Sdougm 		    return (ret);
591*6185db85Sdougm 		/*
592*6185db85Sdougm 		 * probably a legal optionset so check a few more
593*6185db85Sdougm 		 * syntax points below.
594*6185db85Sdougm 		 */
595*6185db85Sdougm 		if (*proto == '\0') {
596*6185db85Sdougm 		    /* not a valid proto (null) */
597*6185db85Sdougm 		    return (ret);
598*6185db85Sdougm 		}
599*6185db85Sdougm 		sectype = strchr(proto, '_');
600*6185db85Sdougm 		if (sectype != NULL)
601*6185db85Sdougm 		    *sectype++ = '\0';
602*6185db85Sdougm 		if (!valid_protocol(proto))
603*6185db85Sdougm 		    return (ret);
604*6185db85Sdougm 	    }
605*6185db85Sdougm 	} else {
606*6185db85Sdougm 	/*
607*6185db85Sdougm 	 * it is ok to not have what we thought since someone might
608*6185db85Sdougm 	 * have added a name via SMF.
609*6185db85Sdougm 	 */
610*6185db85Sdougm 	    return (ret);
611*6185db85Sdougm 	}
612*6185db85Sdougm 
613*6185db85Sdougm 	/*
614*6185db85Sdougm 	 * to get here, we have a valid protocol and possibly a
615*6185db85Sdougm 	 * security. We now have to find the share that it is really
616*6185db85Sdougm 	 * associated with. The "id" portion of the pgroup name will
617*6185db85Sdougm 	 * match.
618*6185db85Sdougm 	 */
619*6185db85Sdougm 
620*6185db85Sdougm 	share = find_share_by_id(id);
621*6185db85Sdougm 	if (share == NULL)
622*6185db85Sdougm 	    return (SA_BAD_PATH);
623*6185db85Sdougm 
624*6185db85Sdougm 	root = (xmlNodePtr)share;
625*6185db85Sdougm 
626*6185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
627*6185db85Sdougm 
628*6185db85Sdougm 	iter = scf_iter_create(handle->handle);
629*6185db85Sdougm 	value = scf_value_create(handle->handle);
630*6185db85Sdougm 	prop = scf_property_create(handle->handle);
631*6185db85Sdougm 	name = malloc(scf_max_name_len);
632*6185db85Sdougm 	valuestr = malloc(vallen);
633*6185db85Sdougm 
634*6185db85Sdougm 	if (sectype == NULL)
635*6185db85Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
636*6185db85Sdougm 	else {
637*6185db85Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL);
638*6185db85Sdougm 	    if (node != NULL)
639*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype);
640*6185db85Sdougm 	}
641*6185db85Sdougm 	if (node != NULL) {
642*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
643*6185db85Sdougm 	    /* now find the properties */
644*6185db85Sdougm 	    if (iter != NULL && value != NULL && prop != NULL && name != NULL) {
645*6185db85Sdougm 		/* iterate over the share pg properties */
646*6185db85Sdougm 		if (scf_iter_pg_properties(iter, pg) == 0) {
647*6185db85Sdougm 		    while (scf_iter_next_property(iter, prop) > 0) {
648*6185db85Sdougm 			ret = SA_SYSTEM_ERR; /* assume the worst */
649*6185db85Sdougm 			if (scf_property_get_name(prop, name,
650*6185db85Sdougm 						    scf_max_name_len) > 0) {
651*6185db85Sdougm 			    if (scf_property_get_value(prop, value) == 0) {
652*6185db85Sdougm 				if (scf_value_get_astring(value, valuestr,
653*6185db85Sdougm 							    vallen) >= 0) {
654*6185db85Sdougm 				    ret = SA_OK;
655*6185db85Sdougm 				}
656*6185db85Sdougm 			    }
657*6185db85Sdougm 			} else {
658*6185db85Sdougm 			    ret = SA_SYSTEM_ERR;
659*6185db85Sdougm 			}
660*6185db85Sdougm 			if (ret == SA_OK) {
661*6185db85Sdougm 			    sa_property_t prop;
662*6185db85Sdougm 			    prop = sa_create_property(name, valuestr);
663*6185db85Sdougm 			    if (prop != NULL)
664*6185db85Sdougm 				prop = (sa_property_t)xmlAddChild(node,
665*6185db85Sdougm 							(xmlNodePtr)prop);
666*6185db85Sdougm 			    else
667*6185db85Sdougm 				ret = SA_NO_MEMORY;
668*6185db85Sdougm 			}
669*6185db85Sdougm 		    }
670*6185db85Sdougm 		} else {
671*6185db85Sdougm 		    ret = SA_SYSTEM_ERR;
672*6185db85Sdougm 		}
673*6185db85Sdougm 	    }
674*6185db85Sdougm 	} else {
675*6185db85Sdougm 	    ret = SA_NO_MEMORY;
676*6185db85Sdougm 	}
677*6185db85Sdougm 	if (iter != NULL)
678*6185db85Sdougm 	    scf_iter_destroy(iter);
679*6185db85Sdougm 	if (value != NULL)
680*6185db85Sdougm 	    scf_value_destroy(value);
681*6185db85Sdougm 	if (prop != NULL)
682*6185db85Sdougm 	    scf_property_destroy(prop);
683*6185db85Sdougm 	if (name != NULL)
684*6185db85Sdougm 	    free(name);
685*6185db85Sdougm 	if (valuestr != NULL)
686*6185db85Sdougm 	    free(valuestr);
687*6185db85Sdougm 	return (ret);
688*6185db85Sdougm }
689*6185db85Sdougm 
690*6185db85Sdougm /*
691*6185db85Sdougm  * sa_extract_group(root, handle, instance)
692*6185db85Sdougm  *
693*6185db85Sdougm  * get the config info for this instance of a group and create the XML
694*6185db85Sdougm  * subtree from it.
695*6185db85Sdougm  */
696*6185db85Sdougm 
697*6185db85Sdougm static int
698*6185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
699*6185db85Sdougm 			scf_instance_t *instance)
700*6185db85Sdougm {
701*6185db85Sdougm 	char *buff;
702*6185db85Sdougm 	xmlNodePtr node;
703*6185db85Sdougm 	scf_iter_t *iter;
704*6185db85Sdougm 	char *proto;
705*6185db85Sdougm 	char *sectype;
706*6185db85Sdougm 	int have_shares = 0;
707*6185db85Sdougm 	int has_proto = 0;
708*6185db85Sdougm 	int is_default = 0;
709*6185db85Sdougm 	int ret = SA_OK;
710*6185db85Sdougm 	int err;
711*6185db85Sdougm 
712*6185db85Sdougm 	buff = malloc(scf_max_name_len);
713*6185db85Sdougm 	iter = scf_iter_create(handle->handle);
714*6185db85Sdougm 	if (buff != NULL) {
715*6185db85Sdougm 	    if (scf_instance_get_name(instance, buff,
716*6185db85Sdougm 						scf_max_name_len) > 0) {
717*6185db85Sdougm 		node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
718*6185db85Sdougm 		if (node != NULL) {
719*6185db85Sdougm 		    xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
720*6185db85Sdougm 		    if (strcmp(buff, "default") == 0)
721*6185db85Sdougm 			is_default++;
722*6185db85Sdougm 		    sa_extract_attrs(node, handle, instance);
723*6185db85Sdougm 			/*
724*6185db85Sdougm 			 * Iterate through all the property groups
725*6185db85Sdougm 			 * looking for those with security or
726*6185db85Sdougm 			 * optionset prefixes. The names of the
727*6185db85Sdougm 			 * matching pgroups are parsed to get the
728*6185db85Sdougm 			 * protocol, and for security, the sectype.
729*6185db85Sdougm 			 * Syntax is as follows:
730*6185db85Sdougm 			 *    optionset | optionset_<proto>
731*6185db85Sdougm 			 *    security_default | security_<proto>_<sectype>
732*6185db85Sdougm 			 * "operation" is handled by
733*6185db85Sdougm 			 * sa_extract_attrs().
734*6185db85Sdougm 			 */
735*6185db85Sdougm 		    if (iter != NULL) {
736*6185db85Sdougm 			if (scf_iter_instance_pgs(iter, instance) == 0) {
737*6185db85Sdougm 			    while (scf_iter_next_pg(iter, handle->pg) > 0) {
738*6185db85Sdougm 				/* have a pgroup so sort it out */
739*6185db85Sdougm 				ret = scf_pg_get_name(handle->pg, buff,
740*6185db85Sdougm 							scf_max_name_len);
741*6185db85Sdougm 				if (ret  > 0) {
742*6185db85Sdougm 				    if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
743*6185db85Sdougm 					sa_share_from_pgroup(node, handle,
744*6185db85Sdougm 								handle->pg,
745*6185db85Sdougm 								buff);
746*6185db85Sdougm 					have_shares++;
747*6185db85Sdougm 				    } else if (strncmp(buff, "optionset", 9) ==
748*6185db85Sdougm 						0) {
749*6185db85Sdougm 					char *nodetype = "optionset";
750*6185db85Sdougm 					/* have an optionset */
751*6185db85Sdougm 					sectype = NULL;
752*6185db85Sdougm 					proto = strchr(buff, '_');
753*6185db85Sdougm 					if (proto != NULL) {
754*6185db85Sdougm 					    *proto++ = '\0';
755*6185db85Sdougm 					    sectype = strchr(proto, '_');
756*6185db85Sdougm 					    if (sectype != NULL) {
757*6185db85Sdougm 						*sectype++ = '\0';
758*6185db85Sdougm 						nodetype = "security";
759*6185db85Sdougm 					    }
760*6185db85Sdougm 					}
761*6185db85Sdougm 					ret = sa_extract_pgroup(node, handle,
762*6185db85Sdougm 							    handle->pg,
763*6185db85Sdougm 							    nodetype,
764*6185db85Sdougm 							    proto, sectype);
765*6185db85Sdougm 					has_proto++;
766*6185db85Sdougm 				    } else if (strncmp(buff,
767*6185db85Sdougm 							"security", 8) == 0) {
768*6185db85Sdougm 					/*
769*6185db85Sdougm 					 * have a security (note that
770*6185db85Sdougm 					 * this should change in the
771*6185db85Sdougm 					 * future)
772*6185db85Sdougm 					 */
773*6185db85Sdougm 					proto = strchr(buff, '_');
774*6185db85Sdougm 					sectype = NULL;
775*6185db85Sdougm 					if (proto != NULL) {
776*6185db85Sdougm 					    *proto++ = '\0';
777*6185db85Sdougm 					    sectype = strchr(proto, '_');
778*6185db85Sdougm 					    if (sectype != NULL)
779*6185db85Sdougm 						*sectype++ = '\0';
780*6185db85Sdougm 					    if (strcmp(proto, "default") == 0)
781*6185db85Sdougm 						proto = NULL;
782*6185db85Sdougm 					}
783*6185db85Sdougm 					ret = sa_extract_pgroup(node, handle,
784*6185db85Sdougm 							    handle->pg,
785*6185db85Sdougm 							    "security", proto,
786*6185db85Sdougm 							    sectype);
787*6185db85Sdougm 					has_proto++;
788*6185db85Sdougm 				    }
789*6185db85Sdougm 				    /* ignore everything else */
790*6185db85Sdougm 				}
791*6185db85Sdougm 			    }
792*6185db85Sdougm 			} else {
793*6185db85Sdougm 			    ret = SA_NO_MEMORY;
794*6185db85Sdougm 			}
795*6185db85Sdougm 			/*
796*6185db85Sdougm 			 * Make sure we have a valid default group.
797*6185db85Sdougm 			 * On first boot, default won't have any
798*6185db85Sdougm 			 * protocols defined and won't be enabled (but
799*6185db85Sdougm 			 * should be).
800*6185db85Sdougm 			 */
801*6185db85Sdougm 			if (is_default) {
802*6185db85Sdougm 			    char *state = sa_get_group_attr((sa_group_t)node,
803*6185db85Sdougm 							    "state");
804*6185db85Sdougm 			    char **protos;
805*6185db85Sdougm 			    int numprotos;
806*6185db85Sdougm 			    int i;
807*6185db85Sdougm 
808*6185db85Sdougm 			    if (state == NULL) {
809*6185db85Sdougm 				/* set attribute to enabled */
810*6185db85Sdougm 				(void) sa_set_group_attr((sa_group_t)node,
811*6185db85Sdougm 							    "state",
812*6185db85Sdougm 							    "enabled");
813*6185db85Sdougm 				/* we can assume no protocols */
814*6185db85Sdougm 				numprotos = sa_get_protocols(&protos);
815*6185db85Sdougm 				for (i = 0; i < numprotos; i++)
816*6185db85Sdougm 				    (void) sa_create_optionset((sa_group_t)node,
817*6185db85Sdougm 								protos[i]);
818*6185db85Sdougm 				if (numprotos > 0)
819*6185db85Sdougm 				    free(protos);
820*6185db85Sdougm 			    } else {
821*6185db85Sdougm 				sa_free_attr_string(state);
822*6185db85Sdougm 			    }
823*6185db85Sdougm 			}
824*6185db85Sdougm 			/* do a second pass if shares were found */
825*6185db85Sdougm 			if (have_shares &&
826*6185db85Sdougm 				scf_iter_instance_pgs(iter, instance) == 0) {
827*6185db85Sdougm 			    while (scf_iter_next_pg(iter, handle->pg) > 0) {
828*6185db85Sdougm 				/*
829*6185db85Sdougm 				 * have a pgroup so see if it is a
830*6185db85Sdougm 				 * share optionset
831*6185db85Sdougm 				 */
832*6185db85Sdougm 				err = scf_pg_get_name(handle->pg, buff,
833*6185db85Sdougm 							scf_max_name_len);
834*6185db85Sdougm 				if (err  > 0) {
835*6185db85Sdougm 				    if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
836*6185db85Sdougm 					ret = sa_share_props_from_pgroup(node,
837*6185db85Sdougm 								handle,
838*6185db85Sdougm 								handle->pg,
839*6185db85Sdougm 								buff);
840*6185db85Sdougm 				    }
841*6185db85Sdougm 				}
842*6185db85Sdougm 			    }
843*6185db85Sdougm 			}
844*6185db85Sdougm 		    }
845*6185db85Sdougm 		}
846*6185db85Sdougm 	    }
847*6185db85Sdougm 	}
848*6185db85Sdougm 	if (iter != NULL)
849*6185db85Sdougm 	    scf_iter_destroy(iter);
850*6185db85Sdougm 	if (buff != NULL)
851*6185db85Sdougm 	    free(buff);
852*6185db85Sdougm 	return (ret);
853*6185db85Sdougm }
854*6185db85Sdougm 
855*6185db85Sdougm /*
856*6185db85Sdougm  * sa_extract_defaults(root, handle, instance)
857*6185db85Sdougm  *
858*6185db85Sdougm  * local function to find the default properties that live in the
859*6185db85Sdougm  * default instance's "operation" proprerty group.
860*6185db85Sdougm  */
861*6185db85Sdougm 
862*6185db85Sdougm static void
863*6185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
864*6185db85Sdougm 		    scf_instance_t *instance)
865*6185db85Sdougm {
866*6185db85Sdougm 	xmlNodePtr node;
867*6185db85Sdougm 	scf_property_t *prop;
868*6185db85Sdougm 	scf_value_t *value;
869*6185db85Sdougm 	char *valuestr;
870*6185db85Sdougm 	ssize_t vallen;
871*6185db85Sdougm 
872*6185db85Sdougm 	vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
873*6185db85Sdougm 	prop = scf_property_create(handle->handle);
874*6185db85Sdougm 	value = scf_value_create(handle->handle);
875*6185db85Sdougm 	valuestr = malloc(vallen);
876*6185db85Sdougm 	if (prop != NULL && value != NULL && vallen != NULL &&
877*6185db85Sdougm 	    scf_instance_get_pg(instance, "operation",
878*6185db85Sdougm 				handle->pg) == 0) {
879*6185db85Sdougm 	    if (scf_pg_get_property(handle->pg,
880*6185db85Sdougm 				    "legacy-timestamp", prop) == 0) {
881*6185db85Sdougm 		/* found the property so get the value */
882*6185db85Sdougm 		if (scf_property_get_value(prop, value) == 0) {
883*6185db85Sdougm 		    if (scf_value_get_astring(value, valuestr, vallen) > 0) {
884*6185db85Sdougm 			node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
885*6185db85Sdougm 					    NULL);
886*6185db85Sdougm 			if (node != NULL) {
887*6185db85Sdougm 			    xmlSetProp(node, (xmlChar *)"timestamp",
888*6185db85Sdougm 					(xmlChar *)valuestr);
889*6185db85Sdougm 			    xmlSetProp(node, (xmlChar *)"path",
890*6185db85Sdougm 					(xmlChar *)SA_LEGACY_DFSTAB);
891*6185db85Sdougm 			}
892*6185db85Sdougm 		    }
893*6185db85Sdougm 		}
894*6185db85Sdougm 	    }
895*6185db85Sdougm 	}
896*6185db85Sdougm 	if (valuestr != NULL)
897*6185db85Sdougm 	    free(valuestr);
898*6185db85Sdougm 	if (value != NULL)
899*6185db85Sdougm 	    scf_value_destroy(value);
900*6185db85Sdougm 	if (prop != NULL)
901*6185db85Sdougm 	    scf_property_destroy(prop);
902*6185db85Sdougm }
903*6185db85Sdougm 
904*6185db85Sdougm 
905*6185db85Sdougm /*
906*6185db85Sdougm  * sa_get_config(handle, root, doc)
907*6185db85Sdougm  *
908*6185db85Sdougm  * walk the SMF repository for /network/shares/group and find all the
909*6185db85Sdougm  * instances. These become group names.  Then add the XML structure
910*6185db85Sdougm  * below the groups based on property groups and properties.
911*6185db85Sdougm  */
912*6185db85Sdougm int
913*6185db85Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc)
914*6185db85Sdougm {
915*6185db85Sdougm 	int ret = SA_OK;
916*6185db85Sdougm 	scf_instance_t *instance;
917*6185db85Sdougm 	scf_iter_t *iter;
918*6185db85Sdougm 	char buff[BUFSIZ * 2];
919*6185db85Sdougm 
920*6185db85Sdougm 	*doc = xmlNewDoc((xmlChar *)"1.0");
921*6185db85Sdougm 	*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
922*6185db85Sdougm 	instance = scf_instance_create(handle->handle);
923*6185db85Sdougm 	iter = scf_iter_create(handle->handle);
924*6185db85Sdougm 	if (*doc != NULL && *root != NULL && instance != NULL && iter != NULL) {
925*6185db85Sdougm 	    xmlDocSetRootElement(*doc, *root);
926*6185db85Sdougm 	    if ((ret = scf_iter_service_instances(iter,
927*6185db85Sdougm 						    handle->service)) == 0) {
928*6185db85Sdougm 		while ((ret = scf_iter_next_instance(iter,
929*6185db85Sdougm 							instance)) > 0) {
930*6185db85Sdougm 		    if (scf_instance_get_name(instance, buff,
931*6185db85Sdougm 						sizeof (buff)) > 0) {
932*6185db85Sdougm 			if (strcmp(buff, "default") == 0)
933*6185db85Sdougm 			    sa_extract_defaults(*root, handle, instance);
934*6185db85Sdougm 			ret = sa_extract_group(*root, handle, instance);
935*6185db85Sdougm 		    }
936*6185db85Sdougm 		}
937*6185db85Sdougm 	    }
938*6185db85Sdougm 	} else {
939*6185db85Sdougm 	    /* if we can't create the document, cleanup */
940*6185db85Sdougm 	    if (*doc != NULL)
941*6185db85Sdougm 		xmlFreeDoc(*doc);
942*6185db85Sdougm 	    if (*root != NULL)
943*6185db85Sdougm 		xmlFreeNode(*root);
944*6185db85Sdougm 	    *doc = NULL;
945*6185db85Sdougm 	    *root = NULL;
946*6185db85Sdougm 	}
947*6185db85Sdougm 	/* always cleanup these */
948*6185db85Sdougm 	if (instance != NULL)
949*6185db85Sdougm 	    scf_instance_destroy(instance);
950*6185db85Sdougm 	if (iter != NULL)
951*6185db85Sdougm 	    scf_iter_destroy(iter);
952*6185db85Sdougm 	return (ret);
953*6185db85Sdougm }
954*6185db85Sdougm 
955*6185db85Sdougm /*
956*6185db85Sdougm  * sa_get_instance(handle, instance)
957*6185db85Sdougm  *
958*6185db85Sdougm  * get the instance of the group service. This is actually the
959*6185db85Sdougm  * specific group name. The instance is needed for all property and
960*6185db85Sdougm  * control operations.
961*6185db85Sdougm  */
962*6185db85Sdougm 
963*6185db85Sdougm int
964*6185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
965*6185db85Sdougm {
966*6185db85Sdougm 	if (scf_service_get_instance(handle->service, instname,
967*6185db85Sdougm 					handle->instance) != 0) {
968*6185db85Sdougm 	    return (SA_NO_SUCH_GROUP);
969*6185db85Sdougm 	}
970*6185db85Sdougm 	return (SA_OK);
971*6185db85Sdougm }
972*6185db85Sdougm 
973*6185db85Sdougm /*
974*6185db85Sdougm  * sa_create_instance(handle, instname)
975*6185db85Sdougm  *
976*6185db85Sdougm  * Create a new SMF service instance. There can only be one with a
977*6185db85Sdougm  * given name.
978*6185db85Sdougm  */
979*6185db85Sdougm 
980*6185db85Sdougm int
981*6185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
982*6185db85Sdougm {
983*6185db85Sdougm 	int ret = SA_OK;
984*6185db85Sdougm 	char instance[SA_GROUP_INST_LEN];
985*6185db85Sdougm 	if (scf_service_add_instance(handle->service, instname,
986*6185db85Sdougm 					handle->instance) != 0) {
987*6185db85Sdougm 	/* better error returns need to be added based on real error */
988*6185db85Sdougm 	    if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
989*6185db85Sdougm 		ret = SA_NO_PERMISSION;
990*6185db85Sdougm 	    else
991*6185db85Sdougm 		ret = SA_DUPLICATE_NAME;
992*6185db85Sdougm 	} else {
993*6185db85Sdougm 	    /* have the service created, so enable it */
994*6185db85Sdougm 	    (void) snprintf(instance, sizeof (instance), "%s:%s",
995*6185db85Sdougm 				SA_SVC_FMRI_BASE, instname);
996*6185db85Sdougm 	    (void) smf_enable_instance(instance, 0);
997*6185db85Sdougm 	}
998*6185db85Sdougm 	return (ret);
999*6185db85Sdougm }
1000*6185db85Sdougm 
1001*6185db85Sdougm /*
1002*6185db85Sdougm  * sa_delete_instance(handle, instname)
1003*6185db85Sdougm  *
1004*6185db85Sdougm  * When a group goes away, we also remove the service instance.
1005*6185db85Sdougm  */
1006*6185db85Sdougm 
1007*6185db85Sdougm int
1008*6185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
1009*6185db85Sdougm {
1010*6185db85Sdougm 	int ret;
1011*6185db85Sdougm 
1012*6185db85Sdougm 	if (strcmp(instname, "default") == 0) {
1013*6185db85Sdougm 	    ret = SA_NO_PERMISSION;
1014*6185db85Sdougm 	} else {
1015*6185db85Sdougm 	    if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
1016*6185db85Sdougm 		if (scf_instance_delete(handle->instance) != 0)
1017*6185db85Sdougm 			/* need better analysis */
1018*6185db85Sdougm 		    ret = SA_NO_PERMISSION;
1019*6185db85Sdougm 	    }
1020*6185db85Sdougm 	}
1021*6185db85Sdougm 	return (ret);
1022*6185db85Sdougm }
1023*6185db85Sdougm 
1024*6185db85Sdougm /*
1025*6185db85Sdougm  * sa_create_pgroup(handle, pgroup)
1026*6185db85Sdougm  *
1027*6185db85Sdougm  * create a new property group
1028*6185db85Sdougm  */
1029*6185db85Sdougm 
1030*6185db85Sdougm int
1031*6185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
1032*6185db85Sdougm {
1033*6185db85Sdougm 	int ret = SA_OK;
1034*6185db85Sdougm 	/*
1035*6185db85Sdougm 	 * only create a handle if it doesn't exist. It is ok to exist
1036*6185db85Sdougm 	 * since the pg handle will be set as a side effect.
1037*6185db85Sdougm 	 */
1038*6185db85Sdougm 	if (handle->pg == NULL) {
1039*6185db85Sdougm 	    handle->pg = scf_pg_create(handle->handle);
1040*6185db85Sdougm 	}
1041*6185db85Sdougm 	/*
1042*6185db85Sdougm 	 * if the pgroup exists, we are done. If it doesn't, then we
1043*6185db85Sdougm 	 * need to actually add one to the service instance.
1044*6185db85Sdougm 	 */
1045*6185db85Sdougm 	if (scf_instance_get_pg(handle->instance,
1046*6185db85Sdougm 				pgroup, handle->pg) != 0) {
1047*6185db85Sdougm 	    /* doesn't exist so create one */
1048*6185db85Sdougm 	    if (scf_instance_add_pg(handle->instance, pgroup,
1049*6185db85Sdougm 				    SCF_GROUP_APPLICATION, 0,
1050*6185db85Sdougm 				    handle->pg) != 0) {
1051*6185db85Sdougm 		switch (scf_error()) {
1052*6185db85Sdougm 		case SCF_ERROR_PERMISSION_DENIED:
1053*6185db85Sdougm 		    ret = SA_NO_PERMISSION;
1054*6185db85Sdougm 		    break;
1055*6185db85Sdougm 		default:
1056*6185db85Sdougm 		    ret = SA_SYSTEM_ERR;
1057*6185db85Sdougm 		    break;
1058*6185db85Sdougm 		}
1059*6185db85Sdougm 	    }
1060*6185db85Sdougm 	}
1061*6185db85Sdougm 	return (ret);
1062*6185db85Sdougm }
1063*6185db85Sdougm 
1064*6185db85Sdougm /*
1065*6185db85Sdougm  * sa_delete_pgroup(handle, pgroup)
1066*6185db85Sdougm  *
1067*6185db85Sdougm  * remove the property group from the current instance of the service,
1068*6185db85Sdougm  * but only if it actually exists.
1069*6185db85Sdougm  */
1070*6185db85Sdougm 
1071*6185db85Sdougm int
1072*6185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
1073*6185db85Sdougm {
1074*6185db85Sdougm 	int ret = SA_OK;
1075*6185db85Sdougm 	/*
1076*6185db85Sdougm 	 * only delete if it does exist.
1077*6185db85Sdougm 	 */
1078*6185db85Sdougm 	if (scf_instance_get_pg(handle->instance,
1079*6185db85Sdougm 				pgroup, handle->pg) == 0) {
1080*6185db85Sdougm 	    /* does exist so delete it */
1081*6185db85Sdougm 	    if (scf_pg_delete(handle->pg) != 0) {
1082*6185db85Sdougm 		ret = SA_SYSTEM_ERR;
1083*6185db85Sdougm 	    }
1084*6185db85Sdougm 	} else {
1085*6185db85Sdougm 	    ret = SA_SYSTEM_ERR;
1086*6185db85Sdougm 	}
1087*6185db85Sdougm 	if (ret == SA_SYSTEM_ERR &&
1088*6185db85Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1089*6185db85Sdougm 		ret = SA_NO_PERMISSION;
1090*6185db85Sdougm 	}
1091*6185db85Sdougm 	return (ret);
1092*6185db85Sdougm }
1093*6185db85Sdougm 
1094*6185db85Sdougm /*
1095*6185db85Sdougm  * sa_start_transaction(handle, pgroup)
1096*6185db85Sdougm  *
1097*6185db85Sdougm  * Start an SMF transaction so we can deal with properties. it would
1098*6185db85Sdougm  * be nice to not have to expose this, but we have to in order to
1099*6185db85Sdougm  * optimize.
1100*6185db85Sdougm  *
1101*6185db85Sdougm  * Basic model is to hold the transaction in the handle and allow
1102*6185db85Sdougm  * property adds/deletes/updates to be added then close the
1103*6185db85Sdougm  * transaction (or abort).  There may eventually be a need to handle
1104*6185db85Sdougm  * other types of transaction mechanisms but we don't do that now.
1105*6185db85Sdougm  *
1106*6185db85Sdougm  * An sa_start_transaction must be followed by either an
1107*6185db85Sdougm  * sa_end_transaction or sa_abort_transaction before another
1108*6185db85Sdougm  * sa_start_transaction can be done.
1109*6185db85Sdougm  */
1110*6185db85Sdougm 
1111*6185db85Sdougm int
1112*6185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
1113*6185db85Sdougm {
1114*6185db85Sdougm 	int ret = SA_OK;
1115*6185db85Sdougm 	/*
1116*6185db85Sdougm 	 * lookup the property group and create it if it doesn't already
1117*6185db85Sdougm 	 * exist.
1118*6185db85Sdougm 	 */
1119*6185db85Sdougm 	if (handle->scf_state == SCH_STATE_INIT) {
1120*6185db85Sdougm 	    ret = sa_create_pgroup(handle, propgroup);
1121*6185db85Sdougm 	    if (ret == SA_OK) {
1122*6185db85Sdougm 		handle->trans = scf_transaction_create(handle->handle);
1123*6185db85Sdougm 		if (handle->trans != NULL) {
1124*6185db85Sdougm 		    if (scf_transaction_start(handle->trans, handle->pg) != 0) {
1125*6185db85Sdougm 			ret = SA_SYSTEM_ERR;
1126*6185db85Sdougm 		    }
1127*6185db85Sdougm 		    if (ret != SA_OK) {
1128*6185db85Sdougm 			scf_transaction_destroy(handle->trans);
1129*6185db85Sdougm 			handle->trans = NULL;
1130*6185db85Sdougm 		    }
1131*6185db85Sdougm 		} else {
1132*6185db85Sdougm 		    ret = SA_SYSTEM_ERR;
1133*6185db85Sdougm 		}
1134*6185db85Sdougm 	    }
1135*6185db85Sdougm 	}
1136*6185db85Sdougm 	if (ret == SA_SYSTEM_ERR &&
1137*6185db85Sdougm 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1138*6185db85Sdougm 		ret = SA_NO_PERMISSION;
1139*6185db85Sdougm 	}
1140*6185db85Sdougm 	return (ret);
1141*6185db85Sdougm }
1142*6185db85Sdougm 
1143*6185db85Sdougm /*
1144*6185db85Sdougm  * sa_end_transaction(handle)
1145*6185db85Sdougm  *
1146*6185db85Sdougm  * Commit the changes that were added to the transaction in the
1147*6185db85Sdougm  * handle. Do all necessary cleanup.
1148*6185db85Sdougm  */
1149*6185db85Sdougm 
1150*6185db85Sdougm int
1151*6185db85Sdougm sa_end_transaction(scfutilhandle_t *handle)
1152*6185db85Sdougm {
1153*6185db85Sdougm 	int ret = SA_OK;
1154*6185db85Sdougm 
1155*6185db85Sdougm 	if (handle->trans == NULL) {
1156*6185db85Sdougm 	    ret = SA_SYSTEM_ERR;
1157*6185db85Sdougm 	} else {
1158*6185db85Sdougm 	    if (scf_transaction_commit(handle->trans) < 0)
1159*6185db85Sdougm 		ret = SA_SYSTEM_ERR;
1160*6185db85Sdougm 	    scf_transaction_destroy_children(handle->trans);
1161*6185db85Sdougm 	    scf_transaction_destroy(handle->trans);
1162*6185db85Sdougm 	    handle->trans = NULL;
1163*6185db85Sdougm 	}
1164*6185db85Sdougm 	return (ret);
1165*6185db85Sdougm }
1166*6185db85Sdougm 
1167*6185db85Sdougm /*
1168*6185db85Sdougm  * sa_abort_transaction(handle)
1169*6185db85Sdougm  *
1170*6185db85Sdougm  * Abort the changes that were added to the transaction in the
1171*6185db85Sdougm  * handle. Do all necessary cleanup.
1172*6185db85Sdougm  */
1173*6185db85Sdougm 
1174*6185db85Sdougm void
1175*6185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle)
1176*6185db85Sdougm {
1177*6185db85Sdougm 	if (handle->trans != NULL) {
1178*6185db85Sdougm 	    scf_transaction_reset_all(handle->trans);
1179*6185db85Sdougm 	    scf_transaction_destroy_children(handle->trans);
1180*6185db85Sdougm 	    scf_transaction_destroy(handle->trans);
1181*6185db85Sdougm 	    handle->trans = NULL;
1182*6185db85Sdougm 	}
1183*6185db85Sdougm }
1184*6185db85Sdougm 
1185*6185db85Sdougm /*
1186*6185db85Sdougm  * sa_set_property(handle, prop, value)
1187*6185db85Sdougm  *
1188*6185db85Sdougm  * set a property transaction entry into the pending SMF transaction.
1189*6185db85Sdougm  */
1190*6185db85Sdougm 
1191*6185db85Sdougm int
1192*6185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
1193*6185db85Sdougm {
1194*6185db85Sdougm 	int ret = SA_OK;
1195*6185db85Sdougm 	scf_value_t *value;
1196*6185db85Sdougm 	scf_transaction_entry_t *entry;
1197*6185db85Sdougm 	/*
1198*6185db85Sdougm 	 * properties must be set in transactions and don't take
1199*6185db85Sdougm 	 * effect until the transaction has been ended/committed.
1200*6185db85Sdougm 	 */
1201*6185db85Sdougm 	value = scf_value_create(handle->handle);
1202*6185db85Sdougm 	entry = scf_entry_create(handle->handle);
1203*6185db85Sdougm 	if (value != NULL && entry != NULL) {
1204*6185db85Sdougm 	    if (scf_transaction_property_change(handle->trans, entry,
1205*6185db85Sdougm 						propname,
1206*6185db85Sdougm 						SCF_TYPE_ASTRING) == 0 ||
1207*6185db85Sdougm 		scf_transaction_property_new(handle->trans, entry,
1208*6185db85Sdougm 						propname,
1209*6185db85Sdougm 						SCF_TYPE_ASTRING) == 0) {
1210*6185db85Sdougm 		if (scf_value_set_astring(value, valstr) == 0) {
1211*6185db85Sdougm 		    if (scf_entry_add_value(entry, value) != 0) {
1212*6185db85Sdougm 			ret = SA_SYSTEM_ERR;
1213*6185db85Sdougm 			scf_value_destroy(value);
1214*6185db85Sdougm 		    }
1215*6185db85Sdougm 		    /* the value is in the transaction */
1216*6185db85Sdougm 		    value = NULL;
1217*6185db85Sdougm 		} else {
1218*6185db85Sdougm 		    /* value couldn't be constructed */
1219*6185db85Sdougm 		    ret = SA_SYSTEM_ERR;
1220*6185db85Sdougm 		}
1221*6185db85Sdougm 		/* the entry is in the transaction */
1222*6185db85Sdougm 		entry = NULL;
1223*6185db85Sdougm 	    } else {
1224*6185db85Sdougm 		ret = SA_SYSTEM_ERR;
1225*6185db85Sdougm 	    }
1226*6185db85Sdougm 	} else {
1227*6185db85Sdougm 	    ret = SA_SYSTEM_ERR;
1228*6185db85Sdougm 	}
1229*6185db85Sdougm 	if (ret == SA_SYSTEM_ERR) {
1230*6185db85Sdougm 	    switch (scf_error()) {
1231*6185db85Sdougm 	    case SCF_ERROR_PERMISSION_DENIED:
1232*6185db85Sdougm 		ret = SA_NO_PERMISSION;
1233*6185db85Sdougm 		break;
1234*6185db85Sdougm 	    }
1235*6185db85Sdougm 	}
1236*6185db85Sdougm 	/*
1237*6185db85Sdougm 	 * cleanup if there were any errors that didn't leave these
1238*6185db85Sdougm 	 * values where they would be cleaned up later.
1239*6185db85Sdougm 	 */
1240*6185db85Sdougm 	if (value != NULL)
1241*6185db85Sdougm 	    scf_value_destroy(value);
1242*6185db85Sdougm 	if (entry != NULL)
1243*6185db85Sdougm 	    scf_entry_destroy(entry);
1244*6185db85Sdougm 	return (ret);
1245*6185db85Sdougm }
1246*6185db85Sdougm 
1247*6185db85Sdougm /*
1248*6185db85Sdougm  * sa_commit_share(handle, group, share)
1249*6185db85Sdougm  *
1250*6185db85Sdougm  *	commit this share to the repository.
1251*6185db85Sdougm  *	properties are added if they exist but can be added later.
1252*6185db85Sdougm  *	Need to add to dfstab and sharetab, if appropriate.
1253*6185db85Sdougm  */
1254*6185db85Sdougm int
1255*6185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1256*6185db85Sdougm {
1257*6185db85Sdougm 	int ret = SA_OK;
1258*6185db85Sdougm 	char *groupname;
1259*6185db85Sdougm 	char *name;
1260*6185db85Sdougm 	char *resource;
1261*6185db85Sdougm 	char *description;
1262*6185db85Sdougm 	char *sharename;
1263*6185db85Sdougm 	ssize_t proplen;
1264*6185db85Sdougm 	char *propstring;
1265*6185db85Sdougm 
1266*6185db85Sdougm 	/*
1267*6185db85Sdougm 	 * don't commit in the zfs group. We do commit legacy
1268*6185db85Sdougm 	 * (default) and all other groups/shares. ZFS is handled
1269*6185db85Sdougm 	 * through the ZFS configuration rather than SMF.
1270*6185db85Sdougm 	 */
1271*6185db85Sdougm 
1272*6185db85Sdougm 	groupname = sa_get_group_attr(group, "name");
1273*6185db85Sdougm 	if (groupname != NULL) {
1274*6185db85Sdougm 	    if (strcmp(groupname, "zfs") == 0) {
1275*6185db85Sdougm 		/*
1276*6185db85Sdougm 		 * adding to the ZFS group will result in the sharenfs
1277*6185db85Sdougm 		 * property being set but we don't want to do anything
1278*6185db85Sdougm 		 * SMF related at this point.
1279*6185db85Sdougm 		 */
1280*6185db85Sdougm 		sa_free_attr_string(groupname);
1281*6185db85Sdougm 		return (ret);
1282*6185db85Sdougm 	    }
1283*6185db85Sdougm 	}
1284*6185db85Sdougm 
1285*6185db85Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1286*6185db85Sdougm 	propstring = malloc(proplen);
1287*6185db85Sdougm 	if (propstring == NULL)
1288*6185db85Sdougm 	    ret = SA_NO_MEMORY;
1289*6185db85Sdougm 
1290*6185db85Sdougm 	if (groupname != NULL && ret == SA_OK) {
1291*6185db85Sdougm 	    ret = sa_get_instance(handle, groupname);
1292*6185db85Sdougm 	    sa_free_attr_string(groupname);
1293*6185db85Sdougm 	    groupname = NULL;
1294*6185db85Sdougm 	    sharename = sa_get_share_attr(share, "id");
1295*6185db85Sdougm 	    if (sharename == NULL) {
1296*6185db85Sdougm 		/* slipped by */
1297*6185db85Sdougm 		char shname[SA_SHARE_UUID_BUFLEN];
1298*6185db85Sdougm 		generate_unique_sharename(shname);
1299*6185db85Sdougm 		xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
1300*6185db85Sdougm 			    (xmlChar *)shname);
1301*6185db85Sdougm 		sharename = strdup(shname);
1302*6185db85Sdougm 	    }
1303*6185db85Sdougm 	    if (sharename != NULL) {
1304*6185db85Sdougm 		/*
1305*6185db85Sdougm 		 * have a share name allocated so create a pgroup
1306*6185db85Sdougm 		 * for it. It may already exist, but that is OK.
1307*6185db85Sdougm 		 */
1308*6185db85Sdougm 		ret = sa_create_pgroup(handle, sharename);
1309*6185db85Sdougm 		if (ret == SA_OK) {
1310*6185db85Sdougm 			/*
1311*6185db85Sdougm 			 * now start the transaction for the
1312*6185db85Sdougm 			 * properties that define this share. They may
1313*6185db85Sdougm 			 * exist so attempt to update before create.
1314*6185db85Sdougm 			 */
1315*6185db85Sdougm 		    ret = sa_start_transaction(handle, sharename);
1316*6185db85Sdougm 		}
1317*6185db85Sdougm 		if (ret == SA_OK) {
1318*6185db85Sdougm 		    name = sa_get_share_attr(share, "path");
1319*6185db85Sdougm 		    if (name != NULL) {
1320*6185db85Sdougm 			/* there needs to be a path for a share to exist */
1321*6185db85Sdougm 			ret = sa_set_property(handle, "path", name);
1322*6185db85Sdougm 			sa_free_attr_string(name);
1323*6185db85Sdougm 		    } else {
1324*6185db85Sdougm 			ret = SA_NO_MEMORY;
1325*6185db85Sdougm 		    }
1326*6185db85Sdougm 		}
1327*6185db85Sdougm 		if (ret == SA_OK) {
1328*6185db85Sdougm 		    resource = sa_get_share_attr(share, "resource");
1329*6185db85Sdougm 		    if (resource != NULL) {
1330*6185db85Sdougm 			ret = sa_set_property(handle, "resource", resource);
1331*6185db85Sdougm 			sa_free_attr_string(resource);
1332*6185db85Sdougm 		    }
1333*6185db85Sdougm 		}
1334*6185db85Sdougm 		if (ret == SA_OK) {
1335*6185db85Sdougm 		    description = sa_get_share_description(share);
1336*6185db85Sdougm 		    if (description != NULL) {
1337*6185db85Sdougm 			ret = sa_set_property(handle, "description",
1338*6185db85Sdougm 						description);
1339*6185db85Sdougm 			sa_free_share_description(description);
1340*6185db85Sdougm 		    }
1341*6185db85Sdougm 		}
1342*6185db85Sdougm 		/* make sure we cleanup the transaction */
1343*6185db85Sdougm 		if (ret == SA_OK) {
1344*6185db85Sdougm 		    ret = sa_end_transaction(handle);
1345*6185db85Sdougm 		} else {
1346*6185db85Sdougm 		    sa_abort_transaction(handle);
1347*6185db85Sdougm 		}
1348*6185db85Sdougm 		free(sharename);
1349*6185db85Sdougm 	    }
1350*6185db85Sdougm 	}
1351*6185db85Sdougm 	if (ret == SA_SYSTEM_ERR) {
1352*6185db85Sdougm 	    int err = scf_error();
1353*6185db85Sdougm 	    if (err == SCF_ERROR_PERMISSION_DENIED)
1354*6185db85Sdougm 		ret = SA_NO_PERMISSION;
1355*6185db85Sdougm 	}
1356*6185db85Sdougm 	if (propstring != NULL)
1357*6185db85Sdougm 	    free(propstring);
1358*6185db85Sdougm 	if (groupname != NULL)
1359*6185db85Sdougm 	    sa_free_attr_string(groupname);
1360*6185db85Sdougm 
1361*6185db85Sdougm 	return (ret);
1362*6185db85Sdougm }
1363*6185db85Sdougm 
1364*6185db85Sdougm /*
1365*6185db85Sdougm  * sa_delete_share(handle, group, share)
1366*6185db85Sdougm  *
1367*6185db85Sdougm  * remove the specified share from the group (and service instance).
1368*6185db85Sdougm  */
1369*6185db85Sdougm 
1370*6185db85Sdougm int
1371*6185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1372*6185db85Sdougm {
1373*6185db85Sdougm 	int ret = SA_OK;
1374*6185db85Sdougm 	char *groupname = NULL;
1375*6185db85Sdougm 	char *shareid = NULL;
1376*6185db85Sdougm 	sa_optionset_t opt;
1377*6185db85Sdougm 	sa_security_t sec;
1378*6185db85Sdougm 	ssize_t proplen;
1379*6185db85Sdougm 	char *propstring;
1380*6185db85Sdougm 
1381*6185db85Sdougm 	proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1382*6185db85Sdougm 	propstring = malloc(proplen);
1383*6185db85Sdougm 	if (propstring == NULL)
1384*6185db85Sdougm 	    ret = SA_NO_MEMORY;
1385*6185db85Sdougm 
1386*6185db85Sdougm 	if (ret == SA_OK) {
1387*6185db85Sdougm 	    groupname = sa_get_group_attr(group, "name");
1388*6185db85Sdougm 	    shareid = sa_get_share_attr(share, "id");
1389*6185db85Sdougm 	    if (groupname != NULL && shareid != NULL) {
1390*6185db85Sdougm 		ret = sa_get_instance(handle, groupname);
1391*6185db85Sdougm 		if (ret == SA_OK) {
1392*6185db85Sdougm 		    /* if a share has properties, remove them */
1393*6185db85Sdougm 		    ret = sa_delete_pgroup(handle, shareid);
1394*6185db85Sdougm 		    for (opt = sa_get_optionset(share, NULL); opt != NULL;
1395*6185db85Sdougm 			opt = sa_get_next_optionset(opt)) {
1396*6185db85Sdougm 			char *proto;
1397*6185db85Sdougm 			proto = sa_get_optionset_attr(opt, "type");
1398*6185db85Sdougm 			if (proto != NULL) {
1399*6185db85Sdougm 			    (void) snprintf(propstring, proplen, "%s_%s",
1400*6185db85Sdougm 						shareid, proto);
1401*6185db85Sdougm 			    ret = sa_delete_pgroup(handle, propstring);
1402*6185db85Sdougm 			    sa_free_attr_string(proto);
1403*6185db85Sdougm 			} else {
1404*6185db85Sdougm 			    ret = SA_NO_MEMORY;
1405*6185db85Sdougm 			}
1406*6185db85Sdougm 		    }
1407*6185db85Sdougm 			/*
1408*6185db85Sdougm 			 * if a share has security/negotiable
1409*6185db85Sdougm 			 * properties, remove them.
1410*6185db85Sdougm 			 */
1411*6185db85Sdougm 		    for (sec = sa_get_security(share, NULL, NULL); sec != NULL;
1412*6185db85Sdougm 			sec = sa_get_next_security(sec)) {
1413*6185db85Sdougm 			char *proto;
1414*6185db85Sdougm 			char *sectype;
1415*6185db85Sdougm 			proto = sa_get_security_attr(sec, "type");
1416*6185db85Sdougm 			sectype = sa_get_security_attr(sec, "sectype");
1417*6185db85Sdougm 			if (proto != NULL && sectype != NULL) {
1418*6185db85Sdougm 			    (void) snprintf(propstring, proplen, "%s_%s_%s",
1419*6185db85Sdougm 					shareid,
1420*6185db85Sdougm 					proto, sectype);
1421*6185db85Sdougm 			    ret = sa_delete_pgroup(handle, propstring);
1422*6185db85Sdougm 			} else {
1423*6185db85Sdougm 			    ret = SA_NO_MEMORY;
1424*6185db85Sdougm 			}
1425*6185db85Sdougm 			if (proto != NULL)
1426*6185db85Sdougm 			    sa_free_attr_string(proto);
1427*6185db85Sdougm 			if (sectype != NULL)
1428*6185db85Sdougm 			    sa_free_attr_string(sectype);
1429*6185db85Sdougm 		    }
1430*6185db85Sdougm 		}
1431*6185db85Sdougm 	    } else {
1432*6185db85Sdougm 		ret = SA_CONFIG_ERR;
1433*6185db85Sdougm 	    }
1434*6185db85Sdougm 	}
1435*6185db85Sdougm 	if (groupname != NULL)
1436*6185db85Sdougm 	    sa_free_attr_string(groupname);
1437*6185db85Sdougm 	if (shareid != NULL)
1438*6185db85Sdougm 	    sa_free_attr_string(shareid);
1439*6185db85Sdougm 	if (propstring != NULL)
1440*6185db85Sdougm 	    free(propstring);
1441*6185db85Sdougm 
1442*6185db85Sdougm 	return (ret);
1443*6185db85Sdougm }
1444