xref: /titanic_50/usr/src/lib/libshare/common/libshare.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 /*
30*6185db85Sdougm  * Share control API
31*6185db85Sdougm  */
32*6185db85Sdougm #include <stdio.h>
33*6185db85Sdougm #include <string.h>
34*6185db85Sdougm #include <ctype.h>
35*6185db85Sdougm #include <sys/types.h>
36*6185db85Sdougm #include <sys/stat.h>
37*6185db85Sdougm #include <unistd.h>
38*6185db85Sdougm #include <libxml/parser.h>
39*6185db85Sdougm #include <libxml/tree.h>
40*6185db85Sdougm #include "libshare.h"
41*6185db85Sdougm #include "libshare_impl.h"
42*6185db85Sdougm #include <libscf.h>
43*6185db85Sdougm #include "scfutil.h"
44*6185db85Sdougm #include <ctype.h>
45*6185db85Sdougm #include <libintl.h>
46*6185db85Sdougm 
47*6185db85Sdougm #if _NOT_SMF
48*6185db85Sdougm #define	CONFIG_FILE	"/var/tmp/share.cfg"
49*6185db85Sdougm #define	CONFIG_FILE_TMP	"/var/tmp/share.cfg.tmp"
50*6185db85Sdougm #endif
51*6185db85Sdougm #define	TSTAMP(tm)	(uint64_t)(((uint64_t)tm.tv_sec << 32) | \
52*6185db85Sdougm 					(tm.tv_nsec & 0xffffffff))
53*6185db85Sdougm 
54*6185db85Sdougm /*
55*6185db85Sdougm  * internal data structures
56*6185db85Sdougm  */
57*6185db85Sdougm 
58*6185db85Sdougm static xmlNodePtr sa_config_tree;	/* the current config */
59*6185db85Sdougm static xmlDocPtr  sa_config_doc = NULL;	/* current config document */
60*6185db85Sdougm extern struct sa_proto_plugin *sap_proto_list;
61*6185db85Sdougm 
62*6185db85Sdougm /* current SMF/SVC repository handle */
63*6185db85Sdougm static scfutilhandle_t *scf_handle = NULL;
64*6185db85Sdougm extern void getlegacyconfig(char *, xmlNodePtr *);
65*6185db85Sdougm extern int gettransients(xmlNodePtr *);
66*6185db85Sdougm extern int sa_valid_property(void *, char *, sa_property_t);
67*6185db85Sdougm extern char *sa_fstype(char *);
68*6185db85Sdougm extern int sa_is_share(void *);
69*6185db85Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
70*6185db85Sdougm extern int sa_group_is_zfs(sa_group_t);
71*6185db85Sdougm extern int sa_path_is_zfs(char *);
72*6185db85Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
73*6185db85Sdougm extern void update_legacy_config(void);
74*6185db85Sdougm extern int issubdir(char *, char *);
75*6185db85Sdougm 
76*6185db85Sdougm static int sa_initialized = 0;
77*6185db85Sdougm 
78*6185db85Sdougm /* helper functions */
79*6185db85Sdougm 
80*6185db85Sdougm char *
81*6185db85Sdougm sa_errorstr(int err)
82*6185db85Sdougm {
83*6185db85Sdougm 	static char errstr[32];
84*6185db85Sdougm 	char *ret = NULL;
85*6185db85Sdougm 
86*6185db85Sdougm 	switch (err) {
87*6185db85Sdougm 	case SA_OK:
88*6185db85Sdougm 	    ret = gettext("ok");
89*6185db85Sdougm 	    break;
90*6185db85Sdougm 	case SA_NO_SUCH_PATH:
91*6185db85Sdougm 	    ret = gettext("path doesn't exist");
92*6185db85Sdougm 	    break;
93*6185db85Sdougm 	case SA_NO_MEMORY:
94*6185db85Sdougm 	    ret = gettext("no memory");
95*6185db85Sdougm 	    break;
96*6185db85Sdougm 	case SA_DUPLICATE_NAME:
97*6185db85Sdougm 	    ret = gettext("name in use");
98*6185db85Sdougm 	    break;
99*6185db85Sdougm 	case SA_BAD_PATH:
100*6185db85Sdougm 	    ret = gettext("bad path");
101*6185db85Sdougm 	    break;
102*6185db85Sdougm 	case SA_NO_SUCH_GROUP:
103*6185db85Sdougm 	    ret = gettext("no such group");
104*6185db85Sdougm 	    break;
105*6185db85Sdougm 	case SA_CONFIG_ERR:
106*6185db85Sdougm 	    ret = gettext("configuration error");
107*6185db85Sdougm 	    break;
108*6185db85Sdougm 	case SA_SYSTEM_ERR:
109*6185db85Sdougm 	    ret = gettext("system error");
110*6185db85Sdougm 	    break;
111*6185db85Sdougm 	case SA_SYNTAX_ERR:
112*6185db85Sdougm 	    ret = gettext("syntax error");
113*6185db85Sdougm 	    break;
114*6185db85Sdougm 	case SA_NO_PERMISSION:
115*6185db85Sdougm 	    ret = gettext("no permission");
116*6185db85Sdougm 	    break;
117*6185db85Sdougm 	case SA_BUSY:
118*6185db85Sdougm 	    ret = gettext("busy");
119*6185db85Sdougm 	    break;
120*6185db85Sdougm 	case SA_NO_SUCH_PROP:
121*6185db85Sdougm 	    ret = gettext("no such property");
122*6185db85Sdougm 	    break;
123*6185db85Sdougm 	case SA_INVALID_NAME:
124*6185db85Sdougm 	    ret = gettext("invalid name");
125*6185db85Sdougm 	    break;
126*6185db85Sdougm 	case SA_INVALID_PROTOCOL:
127*6185db85Sdougm 	    ret = gettext("invalid protocol");
128*6185db85Sdougm 	    break;
129*6185db85Sdougm 	case SA_NOT_ALLOWED:
130*6185db85Sdougm 	    ret = gettext("operation not allowed");
131*6185db85Sdougm 	    break;
132*6185db85Sdougm 	case SA_BAD_VALUE:
133*6185db85Sdougm 	    ret = gettext("bad property value");
134*6185db85Sdougm 	    break;
135*6185db85Sdougm 	case SA_INVALID_SECURITY:
136*6185db85Sdougm 	    ret = gettext("invalid security type");
137*6185db85Sdougm 	    break;
138*6185db85Sdougm 	case SA_NO_SUCH_SECURITY:
139*6185db85Sdougm 	    ret = gettext("security type not found");
140*6185db85Sdougm 	    break;
141*6185db85Sdougm 	case SA_VALUE_CONFLICT:
142*6185db85Sdougm 	    ret = gettext("property value conflict");
143*6185db85Sdougm 	    break;
144*6185db85Sdougm 	case SA_NOT_IMPLEMENTED:
145*6185db85Sdougm 	    ret = gettext("not implemented");
146*6185db85Sdougm 	    break;
147*6185db85Sdougm 	case SA_INVALID_PATH:
148*6185db85Sdougm 	    ret = gettext("invalid path");
149*6185db85Sdougm 	    break;
150*6185db85Sdougm 	case SA_NOT_SUPPORTED:
151*6185db85Sdougm 	    ret = gettext("operation not supported");
152*6185db85Sdougm 	    break;
153*6185db85Sdougm 	case SA_PROP_SHARE_ONLY:
154*6185db85Sdougm 	    ret = gettext("property not valid for group");
155*6185db85Sdougm 	    break;
156*6185db85Sdougm 	case SA_NOT_SHARED:
157*6185db85Sdougm 	    ret = gettext("not shared");
158*6185db85Sdougm 	    break;
159*6185db85Sdougm 	default:
160*6185db85Sdougm 	    (void) snprintf(errstr, sizeof (errstr),
161*6185db85Sdougm 				gettext("unknown %d"), err);
162*6185db85Sdougm 	    ret = errstr;
163*6185db85Sdougm 	}
164*6185db85Sdougm 	return (ret);
165*6185db85Sdougm }
166*6185db85Sdougm 
167*6185db85Sdougm /*
168*6185db85Sdougm  * get_legacy_timestamp(root, path)
169*6185db85Sdougm  *	gets the timestamp of the last time sharemgr updated the legacy
170*6185db85Sdougm  *	files. This is used to determine if someone has modified them by
171*6185db85Sdougm  *	hand.
172*6185db85Sdougm  */
173*6185db85Sdougm static uint64_t
174*6185db85Sdougm get_legacy_timestamp(xmlNodePtr root, char *path)
175*6185db85Sdougm {
176*6185db85Sdougm 	uint64_t tval = 0;
177*6185db85Sdougm 	xmlNodePtr node;
178*6185db85Sdougm 	xmlChar *lpath = NULL;
179*6185db85Sdougm 	xmlChar *timestamp = NULL;
180*6185db85Sdougm 
181*6185db85Sdougm 	for (node = root->xmlChildrenNode; node != NULL;
182*6185db85Sdougm 		node = node->next) {
183*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) {
184*6185db85Sdougm 		/* a possible legacy node for this path */
185*6185db85Sdougm 		lpath = xmlGetProp(node, (xmlChar *)"path");
186*6185db85Sdougm 		if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) {
187*6185db85Sdougm 		    /* now have the node, extract the data */
188*6185db85Sdougm 		    timestamp = xmlGetProp(node, (xmlChar *)"timestamp");
189*6185db85Sdougm 		    if (timestamp != NULL) {
190*6185db85Sdougm 			tval = strtoull((char *)timestamp, NULL, 0);
191*6185db85Sdougm 			break;
192*6185db85Sdougm 		    }
193*6185db85Sdougm 		}
194*6185db85Sdougm 		if (lpath != NULL) {
195*6185db85Sdougm 		    xmlFree(lpath);
196*6185db85Sdougm 		    lpath = NULL;
197*6185db85Sdougm 		}
198*6185db85Sdougm 	    }
199*6185db85Sdougm 	}
200*6185db85Sdougm 	if (lpath != NULL)
201*6185db85Sdougm 	    xmlFree(lpath);
202*6185db85Sdougm 	if (timestamp != NULL)
203*6185db85Sdougm 	    xmlFree(timestamp);
204*6185db85Sdougm 	return (tval);
205*6185db85Sdougm }
206*6185db85Sdougm 
207*6185db85Sdougm /*
208*6185db85Sdougm  * set_legacy_timestamp(root, path, timevalue)
209*6185db85Sdougm  *
210*6185db85Sdougm  * add the current timestamp value to the configuration for use in
211*6185db85Sdougm  * determining when to update the legacy files.  For SMF, this
212*6185db85Sdougm  * property is kept in default/operation/legacy_timestamp
213*6185db85Sdougm  */
214*6185db85Sdougm 
215*6185db85Sdougm static void
216*6185db85Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval)
217*6185db85Sdougm {
218*6185db85Sdougm 	xmlNodePtr node;
219*6185db85Sdougm 	xmlChar *lpath = NULL;
220*6185db85Sdougm 
221*6185db85Sdougm 	for (node = root->xmlChildrenNode; node != NULL;
222*6185db85Sdougm 		node = node->next) {
223*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) {
224*6185db85Sdougm 		/* a possible legacy node for this path */
225*6185db85Sdougm 		lpath = xmlGetProp(node, (xmlChar *)"path");
226*6185db85Sdougm 		if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) {
227*6185db85Sdougm 		    xmlFree(lpath);
228*6185db85Sdougm 		    break;
229*6185db85Sdougm 		}
230*6185db85Sdougm 		if (lpath != NULL)
231*6185db85Sdougm 		    xmlFree(lpath);
232*6185db85Sdougm 	    }
233*6185db85Sdougm 	}
234*6185db85Sdougm 	if (node == NULL) {
235*6185db85Sdougm 	    /* need to create the first legacy timestamp node */
236*6185db85Sdougm 	    node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL);
237*6185db85Sdougm 	}
238*6185db85Sdougm 	if (node != NULL) {
239*6185db85Sdougm 	    char tstring[32];
240*6185db85Sdougm 	    int ret;
241*6185db85Sdougm 
242*6185db85Sdougm 	    (void) snprintf(tstring, sizeof (tstring), "%lld", tval);
243*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring);
244*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path);
245*6185db85Sdougm 	    /* now commit to SMF */
246*6185db85Sdougm 	    ret = sa_get_instance(scf_handle, "default");
247*6185db85Sdougm 	    if (ret == SA_OK) {
248*6185db85Sdougm 		ret = sa_start_transaction(scf_handle, "operation");
249*6185db85Sdougm 		if (ret == SA_OK) {
250*6185db85Sdougm 		    ret = sa_set_property(scf_handle, "legacy-timestamp",
251*6185db85Sdougm 					    tstring);
252*6185db85Sdougm 		    if (ret == SA_OK) {
253*6185db85Sdougm 			(void) sa_end_transaction(scf_handle);
254*6185db85Sdougm 		    } else {
255*6185db85Sdougm 			sa_abort_transaction(scf_handle);
256*6185db85Sdougm 		    }
257*6185db85Sdougm 		}
258*6185db85Sdougm 	    }
259*6185db85Sdougm 	}
260*6185db85Sdougm }
261*6185db85Sdougm 
262*6185db85Sdougm /*
263*6185db85Sdougm  * is_shared(share)
264*6185db85Sdougm  *
265*6185db85Sdougm  * determine if the specified share is currently shared or not.
266*6185db85Sdougm  */
267*6185db85Sdougm static int
268*6185db85Sdougm is_shared(sa_share_t share)
269*6185db85Sdougm {
270*6185db85Sdougm 	char *shared;
271*6185db85Sdougm 	int result = 0; /* assume not */
272*6185db85Sdougm 
273*6185db85Sdougm 	shared = sa_get_share_attr(share, "shared");
274*6185db85Sdougm 	if (shared != NULL) {
275*6185db85Sdougm 	    if (strcmp(shared, "true") == 0)
276*6185db85Sdougm 		result = 1;
277*6185db85Sdougm 	    sa_free_attr_string(shared);
278*6185db85Sdougm 	}
279*6185db85Sdougm 	return (result);
280*6185db85Sdougm }
281*6185db85Sdougm 
282*6185db85Sdougm /*
283*6185db85Sdougm  * checksubdir determines if the specified path is a subdirectory of
284*6185db85Sdougm  * another share. It calls issubdir() from the old share
285*6185db85Sdougm  * implementation to do the complicated work.
286*6185db85Sdougm  */
287*6185db85Sdougm static int
288*6185db85Sdougm checksubdir(char *newpath)
289*6185db85Sdougm {
290*6185db85Sdougm 	sa_group_t group;
291*6185db85Sdougm 	sa_share_t share;
292*6185db85Sdougm 	int issub;
293*6185db85Sdougm 	char *path = NULL;
294*6185db85Sdougm 
295*6185db85Sdougm 	for (issub = 0, group = sa_get_group(NULL);
296*6185db85Sdougm 		group != NULL && !issub;
297*6185db85Sdougm 		group = sa_get_next_group(group)) {
298*6185db85Sdougm 	    for (share = sa_get_share(group, NULL); share != NULL;
299*6185db85Sdougm 		    share = sa_get_next_share(share)) {
300*6185db85Sdougm 		/*
301*6185db85Sdougm 		 * The original behavior of share never checked
302*6185db85Sdougm 		 * against the permanent configuration
303*6185db85Sdougm 		 * (/etc/dfs/dfstab).  PIT has a number of cases where
304*6185db85Sdougm 		 * it depends on this older behavior even though it
305*6185db85Sdougm 		 * could be considered incorrect.  We may tighten this
306*6185db85Sdougm 		 * up in the future.
307*6185db85Sdougm 		 */
308*6185db85Sdougm 		if (!is_shared(share))
309*6185db85Sdougm 		    continue;
310*6185db85Sdougm 
311*6185db85Sdougm 		path = sa_get_share_attr(share, "path");
312*6185db85Sdougm 		if (newpath != NULL &&
313*6185db85Sdougm 		    (strcmp(path, newpath) == 0 || issubdir(newpath, path) ||
314*6185db85Sdougm 			issubdir(path, newpath))) {
315*6185db85Sdougm 		    sa_free_attr_string(path);
316*6185db85Sdougm 		    path = NULL;
317*6185db85Sdougm 		    issub = SA_INVALID_PATH;
318*6185db85Sdougm 		    break;
319*6185db85Sdougm 		}
320*6185db85Sdougm 		sa_free_attr_string(path);
321*6185db85Sdougm 		path = NULL;
322*6185db85Sdougm 	    }
323*6185db85Sdougm 	}
324*6185db85Sdougm 	if (path != NULL)
325*6185db85Sdougm 	    sa_free_attr_string(path);
326*6185db85Sdougm 	return (issub);
327*6185db85Sdougm }
328*6185db85Sdougm 
329*6185db85Sdougm /*
330*6185db85Sdougm  * validpath(path)
331*6185db85Sdougm  * determine if the provided path is valid for a share. It shouldn't
332*6185db85Sdougm  * be a sub-dir of an already shared path or the parent directory of a
333*6185db85Sdougm  * share path.
334*6185db85Sdougm  */
335*6185db85Sdougm static int
336*6185db85Sdougm validpath(char *path)
337*6185db85Sdougm {
338*6185db85Sdougm 	int error = SA_OK;
339*6185db85Sdougm 	struct stat st;
340*6185db85Sdougm 	sa_share_t share;
341*6185db85Sdougm 	char *fstype;
342*6185db85Sdougm 
343*6185db85Sdougm 	if (*path != '/') {
344*6185db85Sdougm 	    return (SA_BAD_PATH);
345*6185db85Sdougm 	}
346*6185db85Sdougm 	if (stat(path, &st) < 0) {
347*6185db85Sdougm 	    error = SA_NO_SUCH_PATH;
348*6185db85Sdougm 	} else {
349*6185db85Sdougm 	    share = sa_find_share(path);
350*6185db85Sdougm 	    if (share != NULL) {
351*6185db85Sdougm 		error = SA_DUPLICATE_NAME;
352*6185db85Sdougm 	    }
353*6185db85Sdougm 	    if (error == SA_OK) {
354*6185db85Sdougm 		/*
355*6185db85Sdougm 		 * check for special case with file system that might
356*6185db85Sdougm 		 * have restrictions.  For now, ZFS is the only case
357*6185db85Sdougm 		 * since it has its own idea of how to configure
358*6185db85Sdougm 		 * shares. We do this before subdir checking since
359*6185db85Sdougm 		 * things like ZFS will do that for us. This should
360*6185db85Sdougm 		 * also be done via plugin interface.
361*6185db85Sdougm 		 */
362*6185db85Sdougm 		fstype = sa_fstype(path);
363*6185db85Sdougm 		if (fstype != NULL && strcmp(fstype, "zfs") == 0) {
364*6185db85Sdougm 		    if (sa_zfs_is_shared(path))
365*6185db85Sdougm 			error = SA_DUPLICATE_NAME;
366*6185db85Sdougm 		}
367*6185db85Sdougm 		if (fstype != NULL)
368*6185db85Sdougm 		    sa_free_fstype(fstype);
369*6185db85Sdougm 	    }
370*6185db85Sdougm 	    if (error == SA_OK) {
371*6185db85Sdougm 		error = checksubdir(path);
372*6185db85Sdougm 	    }
373*6185db85Sdougm 	}
374*6185db85Sdougm 	return (error);
375*6185db85Sdougm }
376*6185db85Sdougm 
377*6185db85Sdougm /*
378*6185db85Sdougm  * check to see if group/share is persistent.
379*6185db85Sdougm  */
380*6185db85Sdougm static int
381*6185db85Sdougm is_persistent(sa_group_t group)
382*6185db85Sdougm {
383*6185db85Sdougm 	char *type;
384*6185db85Sdougm 	int persist = 1;
385*6185db85Sdougm 
386*6185db85Sdougm 	type = sa_get_group_attr(group, "type");
387*6185db85Sdougm 	if (type != NULL && strcmp(type, "transient") == 0)
388*6185db85Sdougm 	    persist = 0;
389*6185db85Sdougm 	if (type != NULL)
390*6185db85Sdougm 	    sa_free_attr_string(type);
391*6185db85Sdougm 	return (persist);
392*6185db85Sdougm }
393*6185db85Sdougm 
394*6185db85Sdougm /*
395*6185db85Sdougm  * sa_valid_group_name(name)
396*6185db85Sdougm  *
397*6185db85Sdougm  * check that the "name" contains only valid characters and otherwise
398*6185db85Sdougm  * fits the required naming conventions. Valid names must start with
399*6185db85Sdougm  * an alphabetic and the remainder may consist of only alphanumeric
400*6185db85Sdougm  * plus the '-' and '_' characters. This name limitation comes from
401*6185db85Sdougm  * inherent limitations in SMF.
402*6185db85Sdougm  */
403*6185db85Sdougm 
404*6185db85Sdougm int
405*6185db85Sdougm sa_valid_group_name(char *name)
406*6185db85Sdougm {
407*6185db85Sdougm 	int ret = 1;
408*6185db85Sdougm 	ssize_t len;
409*6185db85Sdougm 
410*6185db85Sdougm 	if (name != NULL && isalpha(*name)) {
411*6185db85Sdougm 	    char c;
412*6185db85Sdougm 	    len = strlen(name);
413*6185db85Sdougm 	    if (len < (scf_max_name_len - sizeof ("group:"))) {
414*6185db85Sdougm 		for (c = *name++; c != '\0' && ret != 0; c = *name++) {
415*6185db85Sdougm 		    if (!isalnum(c) && c != '-' && c != '_')
416*6185db85Sdougm 			ret = 0;
417*6185db85Sdougm 		}
418*6185db85Sdougm 	    } else {
419*6185db85Sdougm 		ret = 0;
420*6185db85Sdougm 	    }
421*6185db85Sdougm 	} else {
422*6185db85Sdougm 	    ret = 0;
423*6185db85Sdougm 	}
424*6185db85Sdougm 	return (ret);
425*6185db85Sdougm }
426*6185db85Sdougm 
427*6185db85Sdougm 
428*6185db85Sdougm /*
429*6185db85Sdougm  * is_zfs_group(group)
430*6185db85Sdougm  *	Determine if the specified group is a ZFS sharenfs group
431*6185db85Sdougm  */
432*6185db85Sdougm static int
433*6185db85Sdougm is_zfs_group(sa_group_t group)
434*6185db85Sdougm {
435*6185db85Sdougm 	int ret = 0;
436*6185db85Sdougm 	xmlNodePtr parent;
437*6185db85Sdougm 	xmlChar *zfs;
438*6185db85Sdougm 
439*6185db85Sdougm 	if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) {
440*6185db85Sdougm 	    parent = (xmlNodePtr)sa_get_parent_group(group);
441*6185db85Sdougm 	} else {
442*6185db85Sdougm 	    parent = (xmlNodePtr)group;
443*6185db85Sdougm 	}
444*6185db85Sdougm 	zfs = xmlGetProp(parent, (xmlChar *)"zfs");
445*6185db85Sdougm 	if (zfs != NULL) {
446*6185db85Sdougm 	    xmlFree(zfs);
447*6185db85Sdougm 	    ret = 1;
448*6185db85Sdougm 	}
449*6185db85Sdougm 	return (ret);
450*6185db85Sdougm }
451*6185db85Sdougm 
452*6185db85Sdougm /*
453*6185db85Sdougm  * sa_optionset_name(optionset, oname, len, id)
454*6185db85Sdougm  *	return the SMF name for the optionset. If id is not NULL, it
455*6185db85Sdougm  *	will have the GUID value for a share and should be used
456*6185db85Sdougm  *	instead of the keyword "optionset" which is used for
457*6185db85Sdougm  *	groups. If the optionset doesn't have a protocol type
458*6185db85Sdougm  *	associated with it, "default" is used. This shouldn't happen
459*6185db85Sdougm  *	at this point but may be desirable in the future if there are
460*6185db85Sdougm  *	protocol independent properties added. The name is returned in
461*6185db85Sdougm  *	oname.
462*6185db85Sdougm  */
463*6185db85Sdougm 
464*6185db85Sdougm static int
465*6185db85Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id)
466*6185db85Sdougm {
467*6185db85Sdougm 	char *proto;
468*6185db85Sdougm 
469*6185db85Sdougm 	if (id == NULL)
470*6185db85Sdougm 	    id = "optionset";
471*6185db85Sdougm 
472*6185db85Sdougm 	proto = sa_get_optionset_attr(optionset, "type");
473*6185db85Sdougm 	len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default");
474*6185db85Sdougm 
475*6185db85Sdougm 	if (proto != NULL)
476*6185db85Sdougm 	    sa_free_attr_string(proto);
477*6185db85Sdougm 	return (len);
478*6185db85Sdougm }
479*6185db85Sdougm 
480*6185db85Sdougm /*
481*6185db85Sdougm  * sa_security_name(optionset, oname, len, id)
482*6185db85Sdougm  *
483*6185db85Sdougm  * return the SMF name for the security. If id is not NULL, it will
484*6185db85Sdougm  * have the GUID value for a share and should be used instead of the
485*6185db85Sdougm  * keyword "optionset" which is used for groups. If the optionset
486*6185db85Sdougm  * doesn't have a protocol type associated with it, "default" is
487*6185db85Sdougm  * used. This shouldn't happen at this point but may be desirable in
488*6185db85Sdougm  * the future if there are protocol independent properties added. The
489*6185db85Sdougm  * name is returned in oname. The security type is also encoded into
490*6185db85Sdougm  * the name. In the future, this wil *be handled a bit differently.
491*6185db85Sdougm  */
492*6185db85Sdougm 
493*6185db85Sdougm static int
494*6185db85Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id)
495*6185db85Sdougm {
496*6185db85Sdougm 	char *proto;
497*6185db85Sdougm 	char *sectype;
498*6185db85Sdougm 
499*6185db85Sdougm 	if (id == NULL)
500*6185db85Sdougm 	    id = "optionset";
501*6185db85Sdougm 
502*6185db85Sdougm 	proto = sa_get_security_attr(security, "type");
503*6185db85Sdougm 	sectype = sa_get_security_attr(security, "sectype");
504*6185db85Sdougm 	len = snprintf(oname, len, "%s_%s_%s", id,
505*6185db85Sdougm 			    proto ? proto : "default",
506*6185db85Sdougm 			    sectype ? sectype : "default");
507*6185db85Sdougm 	if (proto != NULL)
508*6185db85Sdougm 	    sa_free_attr_string(proto);
509*6185db85Sdougm 	if (sectype != NULL)
510*6185db85Sdougm 	    sa_free_attr_string(sectype);
511*6185db85Sdougm 	return (len);
512*6185db85Sdougm }
513*6185db85Sdougm 
514*6185db85Sdougm /*
515*6185db85Sdougm  * sa_init()
516*6185db85Sdougm  *	Initialize the API
517*6185db85Sdougm  *	find all the shared objects
518*6185db85Sdougm  *	init the tables with all objects
519*6185db85Sdougm  *	read in the current configuration
520*6185db85Sdougm  */
521*6185db85Sdougm 
522*6185db85Sdougm void
523*6185db85Sdougm sa_init(int init_service)
524*6185db85Sdougm {
525*6185db85Sdougm 	struct stat st;
526*6185db85Sdougm 	int legacy = 0;
527*6185db85Sdougm 	uint64_t tval = 0;
528*6185db85Sdougm 
529*6185db85Sdougm 	if (!sa_initialized) {
530*6185db85Sdougm 	    /* get protocol specific structures */
531*6185db85Sdougm 	    (void) proto_plugin_init();
532*6185db85Sdougm 	    if (init_service & SA_INIT_SHARE_API) {
533*6185db85Sdougm 		/*
534*6185db85Sdougm 		 * since we want to use SMF, initialize an svc handle
535*6185db85Sdougm 		 * and find out what is there.
536*6185db85Sdougm 		 */
537*6185db85Sdougm 		scf_handle = sa_scf_init();
538*6185db85Sdougm 		if (scf_handle != NULL) {
539*6185db85Sdougm 		    (void) sa_get_config(scf_handle, &sa_config_tree,
540*6185db85Sdougm 				    &sa_config_doc);
541*6185db85Sdougm 		    tval = get_legacy_timestamp(sa_config_tree,
542*6185db85Sdougm 						SA_LEGACY_DFSTAB);
543*6185db85Sdougm 		    if (tval == 0) {
544*6185db85Sdougm 			/* first time so make sure default is setup */
545*6185db85Sdougm 			sa_group_t defgrp;
546*6185db85Sdougm 			sa_optionset_t opt;
547*6185db85Sdougm 			defgrp = sa_get_group("default");
548*6185db85Sdougm 			if (defgrp != NULL) {
549*6185db85Sdougm 			    opt = sa_get_optionset(defgrp, NULL);
550*6185db85Sdougm 			    if (opt == NULL)
551*6185db85Sdougm 				/* NFS is the default for default */
552*6185db85Sdougm 				opt = sa_create_optionset(defgrp, "nfs");
553*6185db85Sdougm 			}
554*6185db85Sdougm 		    }
555*6185db85Sdougm 		    if (stat(SA_LEGACY_DFSTAB, &st) >= 0 &&
556*6185db85Sdougm 			tval != TSTAMP(st.st_ctim)) {
557*6185db85Sdougm 			getlegacyconfig(SA_LEGACY_DFSTAB, &sa_config_tree);
558*6185db85Sdougm 			if (stat(SA_LEGACY_DFSTAB, &st) >= 0)
559*6185db85Sdougm 			    set_legacy_timestamp(sa_config_tree,
560*6185db85Sdougm 						SA_LEGACY_DFSTAB,
561*6185db85Sdougm 						TSTAMP(st.st_ctim));
562*6185db85Sdougm 		    }
563*6185db85Sdougm 		    legacy |= sa_get_zfs_shares("zfs");
564*6185db85Sdougm 		    legacy |= gettransients(&sa_config_tree);
565*6185db85Sdougm 		}
566*6185db85Sdougm 	    }
567*6185db85Sdougm 	}
568*6185db85Sdougm }
569*6185db85Sdougm 
570*6185db85Sdougm /*
571*6185db85Sdougm  * sa_fini()
572*6185db85Sdougm  *	Uninitialize the API structures including the configuration
573*6185db85Sdougm  *	data structures
574*6185db85Sdougm  */
575*6185db85Sdougm 
576*6185db85Sdougm void
577*6185db85Sdougm sa_fini()
578*6185db85Sdougm {
579*6185db85Sdougm 	if (sa_initialized) {
580*6185db85Sdougm 		/* free the config trees */
581*6185db85Sdougm 		sa_initialized = 0;
582*6185db85Sdougm 		if (sa_config_doc != NULL)
583*6185db85Sdougm 			xmlFreeDoc(sa_config_doc);
584*6185db85Sdougm 		sa_config_tree = NULL;
585*6185db85Sdougm 		sa_config_doc = NULL;
586*6185db85Sdougm 		sa_scf_fini(scf_handle);
587*6185db85Sdougm 		(void) proto_plugin_init();
588*6185db85Sdougm 	}
589*6185db85Sdougm }
590*6185db85Sdougm 
591*6185db85Sdougm /*
592*6185db85Sdougm  * sa_get_protocols(char **protocol)
593*6185db85Sdougm  *	Get array of protocols that are supported
594*6185db85Sdougm  *	Returns pointer to an allocated and NULL terminated
595*6185db85Sdougm  *	array of strings.  Caller must free.
596*6185db85Sdougm  *	This really should be determined dynamically.
597*6185db85Sdougm  *	If there aren't any defined, return -1.
598*6185db85Sdougm  *	Use free() to return memory.
599*6185db85Sdougm  */
600*6185db85Sdougm 
601*6185db85Sdougm int
602*6185db85Sdougm sa_get_protocols(char ***protocols)
603*6185db85Sdougm {
604*6185db85Sdougm 	int numproto = -1;
605*6185db85Sdougm 
606*6185db85Sdougm 	if (protocols != NULL) {
607*6185db85Sdougm 	    struct sa_proto_plugin *plug;
608*6185db85Sdougm 	    for (numproto = 0, plug = sap_proto_list; plug != NULL;
609*6185db85Sdougm 		plug = plug->plugin_next) {
610*6185db85Sdougm 		numproto++;
611*6185db85Sdougm 	    }
612*6185db85Sdougm 
613*6185db85Sdougm 	    *protocols = calloc(numproto + 1,  sizeof (char *));
614*6185db85Sdougm 	    if (*protocols != NULL) {
615*6185db85Sdougm 		int ret = 0;
616*6185db85Sdougm 		for (plug = sap_proto_list; plug != NULL;
617*6185db85Sdougm 		    plug = plug->plugin_next) {
618*6185db85Sdougm 		    /* faking for now */
619*6185db85Sdougm 		    (*protocols)[ret++] = plug->plugin_ops->sa_protocol;
620*6185db85Sdougm 		}
621*6185db85Sdougm 	    } else {
622*6185db85Sdougm 		numproto = -1;
623*6185db85Sdougm 	    }
624*6185db85Sdougm 	}
625*6185db85Sdougm 	return (numproto);
626*6185db85Sdougm }
627*6185db85Sdougm 
628*6185db85Sdougm /*
629*6185db85Sdougm  * find_group_by_name(node, group)
630*6185db85Sdougm  *
631*6185db85Sdougm  * search the XML document subtree specified by node to find the group
632*6185db85Sdougm  * specified by group. Searching subtree allows subgroups to be
633*6185db85Sdougm  * searched for.
634*6185db85Sdougm  */
635*6185db85Sdougm 
636*6185db85Sdougm static xmlNodePtr
637*6185db85Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group)
638*6185db85Sdougm {
639*6185db85Sdougm 	xmlChar *name = NULL;
640*6185db85Sdougm 
641*6185db85Sdougm 	for (node = node->xmlChildrenNode; node != NULL;
642*6185db85Sdougm 	    node = node->next) {
643*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) {
644*6185db85Sdougm 		/* if no groupname, return the first found */
645*6185db85Sdougm 		if (group == NULL)
646*6185db85Sdougm 		    break;
647*6185db85Sdougm 		name = xmlGetProp(node, (xmlChar *)"name");
648*6185db85Sdougm 		if (name != NULL &&
649*6185db85Sdougm 		    xmlStrcmp(name, group) == 0) {
650*6185db85Sdougm 		    break;
651*6185db85Sdougm 		}
652*6185db85Sdougm 		if (name != NULL) {
653*6185db85Sdougm 		    xmlFree(name);
654*6185db85Sdougm 		    name = NULL;
655*6185db85Sdougm 		}
656*6185db85Sdougm 	    }
657*6185db85Sdougm 	}
658*6185db85Sdougm 	if (name != NULL)
659*6185db85Sdougm 	    xmlFree(name);
660*6185db85Sdougm 	return (node);
661*6185db85Sdougm }
662*6185db85Sdougm 
663*6185db85Sdougm /*
664*6185db85Sdougm  * sa_get_group(groupname)
665*6185db85Sdougm  *	Return the "group" specified.  If groupname is NULL,
666*6185db85Sdougm  *	return the first group of the list of groups.
667*6185db85Sdougm  */
668*6185db85Sdougm sa_group_t
669*6185db85Sdougm sa_get_group(char *groupname)
670*6185db85Sdougm {
671*6185db85Sdougm 	xmlNodePtr node = NULL;
672*6185db85Sdougm 	char *subgroup = NULL;
673*6185db85Sdougm 	char *group = NULL;
674*6185db85Sdougm 
675*6185db85Sdougm 	if (sa_config_tree != NULL) {
676*6185db85Sdougm 	    if (groupname != NULL) {
677*6185db85Sdougm 		group = strdup(groupname);
678*6185db85Sdougm 		subgroup = strchr(group, '/');
679*6185db85Sdougm 		if (subgroup != NULL)
680*6185db85Sdougm 		    *subgroup++ = '\0';
681*6185db85Sdougm 	    }
682*6185db85Sdougm 	    node = find_group_by_name(sa_config_tree, (xmlChar *)group);
683*6185db85Sdougm 	    /* if a subgroup, find it before returning */
684*6185db85Sdougm 	    if (subgroup != NULL && node != NULL) {
685*6185db85Sdougm 		node = find_group_by_name(node, (xmlChar *)subgroup);
686*6185db85Sdougm 	    }
687*6185db85Sdougm 	}
688*6185db85Sdougm 	if (node != NULL && (char *)group != NULL)
689*6185db85Sdougm 	    (void) sa_get_instance(scf_handle, (char *)group);
690*6185db85Sdougm 	if (group != NULL)
691*6185db85Sdougm 	    free(group);
692*6185db85Sdougm 	return ((sa_group_t)(node));
693*6185db85Sdougm }
694*6185db85Sdougm 
695*6185db85Sdougm /*
696*6185db85Sdougm  * sa_get_next_group(group)
697*6185db85Sdougm  *	Return the "next" group after the specified group from
698*6185db85Sdougm  *	the internal group list.  NULL if there are no more.
699*6185db85Sdougm  */
700*6185db85Sdougm sa_group_t
701*6185db85Sdougm sa_get_next_group(sa_group_t group)
702*6185db85Sdougm {
703*6185db85Sdougm 	xmlNodePtr ngroup = NULL;
704*6185db85Sdougm 	if (group != NULL) {
705*6185db85Sdougm 	    for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL;
706*6185db85Sdougm 		    ngroup = ngroup->next) {
707*6185db85Sdougm 		if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0)
708*6185db85Sdougm 		    break;
709*6185db85Sdougm 	    }
710*6185db85Sdougm 	}
711*6185db85Sdougm 	return ((sa_group_t)ngroup);
712*6185db85Sdougm }
713*6185db85Sdougm 
714*6185db85Sdougm /*
715*6185db85Sdougm  * sa_get_share(group, sharepath)
716*6185db85Sdougm  *	Return the share object for the share specified. The share
717*6185db85Sdougm  *	must be in the specified group.  Return NULL if not found.
718*6185db85Sdougm  */
719*6185db85Sdougm sa_share_t
720*6185db85Sdougm sa_get_share(sa_group_t group, char *sharepath)
721*6185db85Sdougm {
722*6185db85Sdougm 	xmlNodePtr node = NULL;
723*6185db85Sdougm 	xmlChar *path;
724*6185db85Sdougm 
725*6185db85Sdougm 	/*
726*6185db85Sdougm 	 * For future scalability, this should end up building a cache
727*6185db85Sdougm 	 * since it will get called regularly by the mountd and info
728*6185db85Sdougm 	 * services.
729*6185db85Sdougm 	 */
730*6185db85Sdougm 	if (group != NULL) {
731*6185db85Sdougm 	    for (node = ((xmlNodePtr)group)->children; node != NULL;
732*6185db85Sdougm 		    node = node->next) {
733*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) {
734*6185db85Sdougm 			if (sharepath == NULL) {
735*6185db85Sdougm 				break;
736*6185db85Sdougm 			} else {
737*6185db85Sdougm 				/* is it the correct share? */
738*6185db85Sdougm 			    path = xmlGetProp(node, (xmlChar *)"path");
739*6185db85Sdougm 			    if (path != NULL &&
740*6185db85Sdougm 				xmlStrcmp(path, (xmlChar *)sharepath) == 0) {
741*6185db85Sdougm 				xmlFree(path);
742*6185db85Sdougm 				break;
743*6185db85Sdougm 			    }
744*6185db85Sdougm 			    xmlFree(path);
745*6185db85Sdougm 			}
746*6185db85Sdougm 		}
747*6185db85Sdougm 	    }
748*6185db85Sdougm 	}
749*6185db85Sdougm 	return ((sa_share_t)node);
750*6185db85Sdougm }
751*6185db85Sdougm 
752*6185db85Sdougm /*
753*6185db85Sdougm  * sa_get_next_share(share)
754*6185db85Sdougm  *	Return the next share following the specified share
755*6185db85Sdougm  *	from the internal list of shares. Returns NULL if there
756*6185db85Sdougm  *	are no more shares.  The list is relative to the same
757*6185db85Sdougm  *	group.
758*6185db85Sdougm  */
759*6185db85Sdougm sa_share_t
760*6185db85Sdougm sa_get_next_share(sa_share_t share)
761*6185db85Sdougm {
762*6185db85Sdougm 	xmlNodePtr node = NULL;
763*6185db85Sdougm 
764*6185db85Sdougm 	if (share != NULL) {
765*6185db85Sdougm 	    for (node = ((xmlNodePtr)share)->next; node != NULL;
766*6185db85Sdougm 		    node = node->next) {
767*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) {
768*6185db85Sdougm 			break;
769*6185db85Sdougm 		}
770*6185db85Sdougm 	    }
771*6185db85Sdougm 	}
772*6185db85Sdougm 	return ((sa_share_t)node);
773*6185db85Sdougm }
774*6185db85Sdougm 
775*6185db85Sdougm /*
776*6185db85Sdougm  * _sa_get_child_node(node, type)
777*6185db85Sdougm  *
778*6185db85Sdougm  * find the child node of the specified node that has "type". This is
779*6185db85Sdougm  * used to implement several internal functions.
780*6185db85Sdougm  */
781*6185db85Sdougm 
782*6185db85Sdougm static xmlNodePtr
783*6185db85Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type)
784*6185db85Sdougm {
785*6185db85Sdougm 	xmlNodePtr child;
786*6185db85Sdougm 	for (child = node->xmlChildrenNode; child != NULL;
787*6185db85Sdougm 	    child = child->next)
788*6185db85Sdougm 	    if (xmlStrcmp(child->name, type) == 0)
789*6185db85Sdougm 		return (child);
790*6185db85Sdougm 	return ((xmlNodePtr)NULL);
791*6185db85Sdougm }
792*6185db85Sdougm 
793*6185db85Sdougm /*
794*6185db85Sdougm  *  find_share(group, path)
795*6185db85Sdougm  *
796*6185db85Sdougm  * Search all the shares in the specified group for one that has the
797*6185db85Sdougm  * specified path.
798*6185db85Sdougm  */
799*6185db85Sdougm 
800*6185db85Sdougm static sa_share_t
801*6185db85Sdougm find_share(sa_group_t group, char *sharepath)
802*6185db85Sdougm {
803*6185db85Sdougm 	sa_share_t share;
804*6185db85Sdougm 	char *path;
805*6185db85Sdougm 
806*6185db85Sdougm 	for (share = sa_get_share(group, NULL); share != NULL;
807*6185db85Sdougm 	    share = sa_get_next_share(share)) {
808*6185db85Sdougm 	    path = sa_get_share_attr(share, "path");
809*6185db85Sdougm 	    if (path != NULL && strcmp(path, sharepath) == 0) {
810*6185db85Sdougm 		sa_free_attr_string(path);
811*6185db85Sdougm 		break;
812*6185db85Sdougm 	    }
813*6185db85Sdougm 	    if (path != NULL)
814*6185db85Sdougm 		sa_free_attr_string(path);
815*6185db85Sdougm 	}
816*6185db85Sdougm 	return (share);
817*6185db85Sdougm }
818*6185db85Sdougm 
819*6185db85Sdougm /*
820*6185db85Sdougm  * sa_get_sub_group(group)
821*6185db85Sdougm  *
822*6185db85Sdougm  * Get the first sub-group of group. The sa_get_next_group() function
823*6185db85Sdougm  * can be used to get the rest. This is currently only used for ZFS
824*6185db85Sdougm  * sub-groups but could be used to implement a more general mechanism.
825*6185db85Sdougm  */
826*6185db85Sdougm 
827*6185db85Sdougm sa_group_t
828*6185db85Sdougm sa_get_sub_group(sa_group_t group)
829*6185db85Sdougm {
830*6185db85Sdougm 	return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group,
831*6185db85Sdougm 					    (xmlChar *)"group"));
832*6185db85Sdougm }
833*6185db85Sdougm 
834*6185db85Sdougm /*
835*6185db85Sdougm  * sa_find_share(sharepath)
836*6185db85Sdougm  *	Finds a share regardless of group.  In the future, this
837*6185db85Sdougm  *	function should utilize a cache and hash table of some kind.
838*6185db85Sdougm  *	The current assumption is that a path will only be shared
839*6185db85Sdougm  *	once.  In the future, this may change as implementation of
840*6185db85Sdougm  *	resource names comes into being.
841*6185db85Sdougm  */
842*6185db85Sdougm sa_share_t
843*6185db85Sdougm sa_find_share(char *sharepath)
844*6185db85Sdougm {
845*6185db85Sdougm 	sa_group_t group;
846*6185db85Sdougm 	sa_group_t zgroup;
847*6185db85Sdougm 	sa_share_t share = NULL;
848*6185db85Sdougm 	int done = 0;
849*6185db85Sdougm 
850*6185db85Sdougm 	for (group = sa_get_group(NULL); group != NULL && !done;
851*6185db85Sdougm 		group = sa_get_next_group(group)) {
852*6185db85Sdougm 	    if (is_zfs_group(group)) {
853*6185db85Sdougm 		for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
854*6185db85Sdougm 							(xmlChar *)"group");
855*6185db85Sdougm 		    zgroup != NULL; zgroup = sa_get_next_group(zgroup)) {
856*6185db85Sdougm 		    share = find_share(zgroup, sharepath);
857*6185db85Sdougm 		    if (share != NULL)
858*6185db85Sdougm 			break;
859*6185db85Sdougm 		}
860*6185db85Sdougm 	    } else {
861*6185db85Sdougm 		share = find_share(group, sharepath);
862*6185db85Sdougm 	    }
863*6185db85Sdougm 	    if (share != NULL)
864*6185db85Sdougm 		break;
865*6185db85Sdougm 	}
866*6185db85Sdougm 	return (share);
867*6185db85Sdougm }
868*6185db85Sdougm 
869*6185db85Sdougm /*
870*6185db85Sdougm  *  sa_check_path(group, path)
871*6185db85Sdougm  *
872*6185db85Sdougm  * check that path is a valid path relative to the group.  Currently,
873*6185db85Sdougm  * we are ignoring the group and checking only the NFS rules. Later,
874*6185db85Sdougm  * we may want to use the group to then check against the protocols
875*6185db85Sdougm  * enabled on the group.
876*6185db85Sdougm  */
877*6185db85Sdougm 
878*6185db85Sdougm int
879*6185db85Sdougm sa_check_path(sa_group_t group, char *path)
880*6185db85Sdougm {
881*6185db85Sdougm #ifdef lint
882*6185db85Sdougm 	group = group;
883*6185db85Sdougm #endif
884*6185db85Sdougm 	return (validpath(path));
885*6185db85Sdougm }
886*6185db85Sdougm 
887*6185db85Sdougm /*
888*6185db85Sdougm  * _sa_add_share(group, sharepath, persist, *error)
889*6185db85Sdougm  *
890*6185db85Sdougm  * common code for all types of add_share. sa_add_share() is the
891*6185db85Sdougm  * public API, we also need to be able to do this when parsing legacy
892*6185db85Sdougm  * files and construction of the internal configuration while
893*6185db85Sdougm  * extracting config info from SMF.
894*6185db85Sdougm  */
895*6185db85Sdougm 
896*6185db85Sdougm sa_share_t
897*6185db85Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
898*6185db85Sdougm {
899*6185db85Sdougm 	xmlNodePtr node = NULL;
900*6185db85Sdougm 	int err;
901*6185db85Sdougm 
902*6185db85Sdougm 	err  = SA_OK; /* assume success */
903*6185db85Sdougm 
904*6185db85Sdougm 	node = xmlNewChild((xmlNodePtr)group, NULL,
905*6185db85Sdougm 				(xmlChar *)"share", NULL);
906*6185db85Sdougm 	if (node != NULL) {
907*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
908*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"type", persist ?
909*6185db85Sdougm 			(xmlChar *)"persist" : (xmlChar *)"transient");
910*6185db85Sdougm 	    if (persist != SA_SHARE_TRANSIENT) {
911*6185db85Sdougm 		/*
912*6185db85Sdougm 		 * persistent shares come in two flavors: SMF and
913*6185db85Sdougm 		 * ZFS. Sort this one out based on target group and
914*6185db85Sdougm 		 * path type. Currently, only NFS is supported in the
915*6185db85Sdougm 		 * ZFS group and it is always on.
916*6185db85Sdougm 		 */
917*6185db85Sdougm 		if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) {
918*6185db85Sdougm 		    err = sa_zfs_set_sharenfs(group, sharepath, 1);
919*6185db85Sdougm 		} else {
920*6185db85Sdougm 		    err = sa_commit_share(scf_handle, group,
921*6185db85Sdougm 						(sa_share_t)node);
922*6185db85Sdougm 		}
923*6185db85Sdougm 	    }
924*6185db85Sdougm 	    if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) {
925*6185db85Sdougm 		/* called by the dfstab parser so could be a show */
926*6185db85Sdougm 		err = SA_OK;
927*6185db85Sdougm 	    }
928*6185db85Sdougm 	    if (err != SA_OK) {
929*6185db85Sdougm 		/*
930*6185db85Sdougm 		 * we couldn't commit to the repository so undo
931*6185db85Sdougm 		 * our internal state to reflect reality.
932*6185db85Sdougm 		 */
933*6185db85Sdougm 		xmlUnlinkNode(node);
934*6185db85Sdougm 		xmlFreeNode(node);
935*6185db85Sdougm 		node = NULL;
936*6185db85Sdougm 	    }
937*6185db85Sdougm 	} else {
938*6185db85Sdougm 	    err = SA_NO_MEMORY;
939*6185db85Sdougm 	}
940*6185db85Sdougm 	if (error != NULL)
941*6185db85Sdougm 	    *error = err;
942*6185db85Sdougm 	return (node);
943*6185db85Sdougm }
944*6185db85Sdougm 
945*6185db85Sdougm /*
946*6185db85Sdougm  * sa_add_share(group, sharepath, persist, *error)
947*6185db85Sdougm  *
948*6185db85Sdougm  *	Add a new share object to the specified group.  The share will
949*6185db85Sdougm  *	have the specified sharepath and will only be constructed if
950*6185db85Sdougm  *	it is a valid path to be shared.  NULL is returned on error
951*6185db85Sdougm  *	and a detailed error value will be returned via the error
952*6185db85Sdougm  *	pointer.
953*6185db85Sdougm  */
954*6185db85Sdougm sa_share_t
955*6185db85Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
956*6185db85Sdougm {
957*6185db85Sdougm 	xmlNodePtr node = NULL;
958*6185db85Sdougm 	sa_share_t dup;
959*6185db85Sdougm 
960*6185db85Sdougm 	if ((dup = sa_find_share(sharepath)) == NULL &&
961*6185db85Sdougm 		(*error = sa_check_path(group, sharepath)) == SA_OK) {
962*6185db85Sdougm 	    node = _sa_add_share(group, sharepath, persist, error);
963*6185db85Sdougm 	}
964*6185db85Sdougm 	if (dup != NULL)
965*6185db85Sdougm 	    *error = SA_DUPLICATE_NAME;
966*6185db85Sdougm 
967*6185db85Sdougm 	return ((sa_share_t)node);
968*6185db85Sdougm }
969*6185db85Sdougm 
970*6185db85Sdougm /*
971*6185db85Sdougm  * sa_enable_share(share, protocol)
972*6185db85Sdougm  *	Enable the specified share to the specified protocol.
973*6185db85Sdougm  *	If protocol is NULL, then all protocols.
974*6185db85Sdougm  */
975*6185db85Sdougm int
976*6185db85Sdougm sa_enable_share(sa_share_t share, char *protocol)
977*6185db85Sdougm {
978*6185db85Sdougm 	char *sharepath;
979*6185db85Sdougm 	struct stat st;
980*6185db85Sdougm 	int err = 0;
981*6185db85Sdougm 
982*6185db85Sdougm 	sharepath = sa_get_share_attr(share, "path");
983*6185db85Sdougm 	if (stat(sharepath, &st) < 0) {
984*6185db85Sdougm 	    err = SA_NO_SUCH_PATH;
985*6185db85Sdougm 	} else {
986*6185db85Sdougm 	    /* tell the server about the share */
987*6185db85Sdougm 	    if (protocol != NULL) {
988*6185db85Sdougm 		/* lookup protocol specific handler */
989*6185db85Sdougm 		err = sa_proto_share(protocol, share);
990*6185db85Sdougm 		if (err == SA_OK)
991*6185db85Sdougm 		    (void) sa_set_share_attr(share, "shared", "true");
992*6185db85Sdougm 	    } else {
993*6185db85Sdougm 		/* tell all protocols */
994*6185db85Sdougm 		err = sa_proto_share("nfs", share); /* only NFS for now */
995*6185db85Sdougm 		(void) sa_set_share_attr(share, "shared", "true");
996*6185db85Sdougm 	    }
997*6185db85Sdougm 	}
998*6185db85Sdougm 	if (sharepath != NULL)
999*6185db85Sdougm 	    sa_free_attr_string(sharepath);
1000*6185db85Sdougm 	return (err);
1001*6185db85Sdougm }
1002*6185db85Sdougm 
1003*6185db85Sdougm /*
1004*6185db85Sdougm  * sa_disable_share(share, protocol)
1005*6185db85Sdougm  *	Disable the specified share to the specified protocol.
1006*6185db85Sdougm  *	If protocol is NULL, then all protocols.
1007*6185db85Sdougm  */
1008*6185db85Sdougm int
1009*6185db85Sdougm sa_disable_share(sa_share_t share, char *protocol)
1010*6185db85Sdougm {
1011*6185db85Sdougm 	char *path;
1012*6185db85Sdougm 	char *shared;
1013*6185db85Sdougm 	int ret = SA_OK;
1014*6185db85Sdougm 
1015*6185db85Sdougm 	path = sa_get_share_attr(share, "path");
1016*6185db85Sdougm 	shared = sa_get_share_attr(share, "shared");
1017*6185db85Sdougm 
1018*6185db85Sdougm 	if (protocol != NULL) {
1019*6185db85Sdougm 	    ret = sa_proto_unshare(protocol, path);
1020*6185db85Sdougm 	} else {
1021*6185db85Sdougm 	    /* need to do all protocols */
1022*6185db85Sdougm 	    ret = sa_proto_unshare("nfs", path);
1023*6185db85Sdougm 	}
1024*6185db85Sdougm 	if (ret == SA_OK)
1025*6185db85Sdougm 		(void) sa_set_share_attr(share, "shared", NULL);
1026*6185db85Sdougm 	if (path != NULL)
1027*6185db85Sdougm 	    sa_free_attr_string(path);
1028*6185db85Sdougm 	if (shared != NULL)
1029*6185db85Sdougm 	    sa_free_attr_string(shared);
1030*6185db85Sdougm 	return (ret);
1031*6185db85Sdougm }
1032*6185db85Sdougm 
1033*6185db85Sdougm /*
1034*6185db85Sdougm  * sa_remove_share(share)
1035*6185db85Sdougm  *
1036*6185db85Sdougm  * remove the specified share from its containing group.
1037*6185db85Sdougm  * Remove from the SMF or ZFS configuration space.
1038*6185db85Sdougm  */
1039*6185db85Sdougm 
1040*6185db85Sdougm int
1041*6185db85Sdougm sa_remove_share(sa_share_t share)
1042*6185db85Sdougm {
1043*6185db85Sdougm 	sa_group_t group;
1044*6185db85Sdougm 	int ret = SA_OK;
1045*6185db85Sdougm 	char *type;
1046*6185db85Sdougm 	int transient = 0;
1047*6185db85Sdougm 	char *groupname;
1048*6185db85Sdougm 	char *zfs;
1049*6185db85Sdougm 
1050*6185db85Sdougm 	type = sa_get_share_attr(share, "type");
1051*6185db85Sdougm 	group = sa_get_parent_group(share);
1052*6185db85Sdougm 	zfs = sa_get_group_attr(group, "zfs");
1053*6185db85Sdougm 	groupname = sa_get_group_attr(group, "name");
1054*6185db85Sdougm 	if (type != NULL && strcmp(type, "persist") != 0)
1055*6185db85Sdougm 	    transient = 1;
1056*6185db85Sdougm 	if (type != NULL)
1057*6185db85Sdougm 	    sa_free_attr_string(type);
1058*6185db85Sdougm 
1059*6185db85Sdougm 	/* remove the node from its group then free the memory */
1060*6185db85Sdougm 
1061*6185db85Sdougm 	/*
1062*6185db85Sdougm 	 * need to test if "busy"
1063*6185db85Sdougm 	 */
1064*6185db85Sdougm 	/* only do SMF action if permanent */
1065*6185db85Sdougm 	if (!transient || zfs != NULL) {
1066*6185db85Sdougm 	    /* remove from legacy dfstab as well as possible SMF */
1067*6185db85Sdougm 	    ret = sa_delete_legacy(share);
1068*6185db85Sdougm 	    if (ret == SA_OK) {
1069*6185db85Sdougm 		if (!sa_group_is_zfs(group)) {
1070*6185db85Sdougm 		    ret = sa_delete_share(scf_handle, group, share);
1071*6185db85Sdougm 		} else {
1072*6185db85Sdougm 		    char *sharepath = sa_get_share_attr(share, "path");
1073*6185db85Sdougm 		    if (sharepath != NULL) {
1074*6185db85Sdougm 			ret = sa_zfs_set_sharenfs(group, sharepath, 0);
1075*6185db85Sdougm 			sa_free_attr_string(sharepath);
1076*6185db85Sdougm 		    }
1077*6185db85Sdougm 		}
1078*6185db85Sdougm 	    }
1079*6185db85Sdougm 	}
1080*6185db85Sdougm 	if (groupname != NULL)
1081*6185db85Sdougm 	    sa_free_attr_string(groupname);
1082*6185db85Sdougm 	if (zfs != NULL)
1083*6185db85Sdougm 	    sa_free_attr_string(zfs);
1084*6185db85Sdougm 
1085*6185db85Sdougm 	xmlUnlinkNode((xmlNodePtr)share);
1086*6185db85Sdougm 	xmlFreeNode((xmlNodePtr)share);
1087*6185db85Sdougm 	return (ret);
1088*6185db85Sdougm }
1089*6185db85Sdougm 
1090*6185db85Sdougm /*
1091*6185db85Sdougm  * sa_move_share(group, share)
1092*6185db85Sdougm  *
1093*6185db85Sdougm  * move the specified share to the specified group.  Update SMF
1094*6185db85Sdougm  * appropriately.
1095*6185db85Sdougm  */
1096*6185db85Sdougm 
1097*6185db85Sdougm int
1098*6185db85Sdougm sa_move_share(sa_group_t group, sa_share_t share)
1099*6185db85Sdougm {
1100*6185db85Sdougm 	sa_group_t oldgroup;
1101*6185db85Sdougm 	int ret = SA_OK;
1102*6185db85Sdougm 
1103*6185db85Sdougm 	/* remove the node from its group then free the memory */
1104*6185db85Sdougm 
1105*6185db85Sdougm 	oldgroup = sa_get_parent_group(share);
1106*6185db85Sdougm 	if (oldgroup != group) {
1107*6185db85Sdougm 	    xmlUnlinkNode((xmlNodePtr)share);
1108*6185db85Sdougm 	    /* now that the share isn't in its old group, add to the new one */
1109*6185db85Sdougm 	    xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
1110*6185db85Sdougm 	    /* need to deal with SMF */
1111*6185db85Sdougm 	    if (ret == SA_OK) {
1112*6185db85Sdougm 		/*
1113*6185db85Sdougm 		 * need to remove from old group first and then add to
1114*6185db85Sdougm 		 * new group. Ideally, we would do the other order but
1115*6185db85Sdougm 		 * need to avoid having the share in two groups at the
1116*6185db85Sdougm 		 * same time.
1117*6185db85Sdougm 		 */
1118*6185db85Sdougm 		ret = sa_delete_share(scf_handle, oldgroup, share);
1119*6185db85Sdougm 	    }
1120*6185db85Sdougm 	    ret = sa_commit_share(scf_handle, group, share);
1121*6185db85Sdougm 	}
1122*6185db85Sdougm 	return (ret);
1123*6185db85Sdougm }
1124*6185db85Sdougm 
1125*6185db85Sdougm /*
1126*6185db85Sdougm  * sa_get_parent_group(share)
1127*6185db85Sdougm  *
1128*6185db85Sdougm  * Return the containg group for the share. If a group was actually
1129*6185db85Sdougm  * passed in, we don't want a parent so return NULL.
1130*6185db85Sdougm  */
1131*6185db85Sdougm 
1132*6185db85Sdougm sa_group_t
1133*6185db85Sdougm sa_get_parent_group(sa_share_t share)
1134*6185db85Sdougm {
1135*6185db85Sdougm 	xmlNodePtr node = NULL;
1136*6185db85Sdougm 	if (share != NULL) {
1137*6185db85Sdougm 	    node = ((xmlNodePtr)share)->parent;
1138*6185db85Sdougm 		/*
1139*6185db85Sdougm 		 * make sure parent is a group and not sharecfg since
1140*6185db85Sdougm 		 * we may be cheating and passing in a group.
1141*6185db85Sdougm 		 * Eventually, groups of groups might come into being.
1142*6185db85Sdougm 		 */
1143*6185db85Sdougm 	    if (node == NULL ||
1144*6185db85Sdougm 		xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0)
1145*6185db85Sdougm 		node = NULL;
1146*6185db85Sdougm 	}
1147*6185db85Sdougm 	return ((sa_group_t)node);
1148*6185db85Sdougm }
1149*6185db85Sdougm 
1150*6185db85Sdougm /*
1151*6185db85Sdougm  * _sa_create_group(groupname)
1152*6185db85Sdougm  *
1153*6185db85Sdougm  * Create a group in the document. The caller will need to deal with
1154*6185db85Sdougm  * configuration store and activation.
1155*6185db85Sdougm  */
1156*6185db85Sdougm 
1157*6185db85Sdougm sa_group_t
1158*6185db85Sdougm _sa_create_group(char *groupname)
1159*6185db85Sdougm {
1160*6185db85Sdougm 	xmlNodePtr node = NULL;
1161*6185db85Sdougm 
1162*6185db85Sdougm 	if (sa_valid_group_name(groupname)) {
1163*6185db85Sdougm 	    node = xmlNewChild(sa_config_tree, NULL,
1164*6185db85Sdougm 				(xmlChar *)"group", NULL);
1165*6185db85Sdougm 	    if (node != NULL) {
1166*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname);
1167*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled");
1168*6185db85Sdougm 	    }
1169*6185db85Sdougm 	}
1170*6185db85Sdougm 	return ((sa_group_t)node);
1171*6185db85Sdougm }
1172*6185db85Sdougm 
1173*6185db85Sdougm /*
1174*6185db85Sdougm  * _sa_create_zfs_group(group, groupname)
1175*6185db85Sdougm  *
1176*6185db85Sdougm  * Create a ZFS subgroup under the specified group. This may
1177*6185db85Sdougm  * eventually form the basis of general sub-groups, but is currently
1178*6185db85Sdougm  * restricted to ZFS.
1179*6185db85Sdougm  */
1180*6185db85Sdougm sa_group_t
1181*6185db85Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname)
1182*6185db85Sdougm {
1183*6185db85Sdougm 	xmlNodePtr node = NULL;
1184*6185db85Sdougm 
1185*6185db85Sdougm 	node = xmlNewChild((xmlNodePtr)group, NULL,
1186*6185db85Sdougm 				(xmlChar *)"group", NULL);
1187*6185db85Sdougm 	if (node != NULL) {
1188*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname);
1189*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled");
1190*6185db85Sdougm 	}
1191*6185db85Sdougm 
1192*6185db85Sdougm 	return ((sa_group_t)node);
1193*6185db85Sdougm }
1194*6185db85Sdougm 
1195*6185db85Sdougm /*
1196*6185db85Sdougm  * sa_create_group(groupname, *error)
1197*6185db85Sdougm  *
1198*6185db85Sdougm  * Create a new group with groupname.  Need to validate that it is a
1199*6185db85Sdougm  * legal name for SMF and the construct the SMF service instance of
1200*6185db85Sdougm  * svc:/network/shares/group to implement the group. All necessary
1201*6185db85Sdougm  * operational properties must be added to the group at this point
1202*6185db85Sdougm  * (via the SMF transaction model).
1203*6185db85Sdougm  */
1204*6185db85Sdougm sa_group_t
1205*6185db85Sdougm sa_create_group(char *groupname, int *error)
1206*6185db85Sdougm {
1207*6185db85Sdougm 	xmlNodePtr node = NULL;
1208*6185db85Sdougm 	sa_group_t group;
1209*6185db85Sdougm 	int ret;
1210*6185db85Sdougm 	char rbacstr[256];
1211*6185db85Sdougm 
1212*6185db85Sdougm 	ret = SA_OK;
1213*6185db85Sdougm 
1214*6185db85Sdougm 	if (scf_handle == NULL) {
1215*6185db85Sdougm 	    ret = SA_SYSTEM_ERR;
1216*6185db85Sdougm 	    goto err;
1217*6185db85Sdougm 	}
1218*6185db85Sdougm 
1219*6185db85Sdougm 	group = sa_get_group(groupname);
1220*6185db85Sdougm 	if (group != NULL) {
1221*6185db85Sdougm 	    ret = SA_DUPLICATE_NAME;
1222*6185db85Sdougm 	} else {
1223*6185db85Sdougm 	    if (sa_valid_group_name(groupname)) {
1224*6185db85Sdougm 		node = xmlNewChild(sa_config_tree, NULL,
1225*6185db85Sdougm 				    (xmlChar *)"group", NULL);
1226*6185db85Sdougm 		if (node != NULL) {
1227*6185db85Sdougm 		    xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname);
1228*6185db85Sdougm 		    /* default to the group being enabled */
1229*6185db85Sdougm 		    xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled");
1230*6185db85Sdougm 		    ret = sa_create_instance(scf_handle, groupname);
1231*6185db85Sdougm 		    if (ret == SA_OK) {
1232*6185db85Sdougm 			ret = sa_start_transaction(scf_handle, "operation");
1233*6185db85Sdougm 		    }
1234*6185db85Sdougm 		    if (ret == SA_OK) {
1235*6185db85Sdougm 			ret = sa_set_property(scf_handle, "state", "enabled");
1236*6185db85Sdougm 			if (ret == SA_OK) {
1237*6185db85Sdougm 			    ret = sa_end_transaction(scf_handle);
1238*6185db85Sdougm 			} else {
1239*6185db85Sdougm 			    sa_abort_transaction(scf_handle);
1240*6185db85Sdougm 			}
1241*6185db85Sdougm 		    }
1242*6185db85Sdougm 		    if (ret == SA_OK) {
1243*6185db85Sdougm 			/* initialize the RBAC strings */
1244*6185db85Sdougm 			ret = sa_start_transaction(scf_handle, "general");
1245*6185db85Sdougm 			if (ret == SA_OK) {
1246*6185db85Sdougm 			    (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s",
1247*6185db85Sdougm 					SA_RBAC_MANAGE, groupname);
1248*6185db85Sdougm 			    ret = sa_set_property(scf_handle,
1249*6185db85Sdougm 						    "action_authorization",
1250*6185db85Sdougm 						    rbacstr);
1251*6185db85Sdougm 			}
1252*6185db85Sdougm 			if (ret == SA_OK) {
1253*6185db85Sdougm 			    (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s",
1254*6185db85Sdougm 					SA_RBAC_VALUE, groupname);
1255*6185db85Sdougm 			    ret = sa_set_property(scf_handle,
1256*6185db85Sdougm 						    "value_authorization",
1257*6185db85Sdougm 						    rbacstr);
1258*6185db85Sdougm 			}
1259*6185db85Sdougm 			if (ret == SA_OK) {
1260*6185db85Sdougm 			    ret = sa_end_transaction(scf_handle);
1261*6185db85Sdougm 			} else {
1262*6185db85Sdougm 			    sa_abort_transaction(scf_handle);
1263*6185db85Sdougm 			}
1264*6185db85Sdougm 		    }
1265*6185db85Sdougm 		    if (ret != SA_OK) {
1266*6185db85Sdougm 			/*
1267*6185db85Sdougm 			 * Couldn't commit the group so we need to
1268*6185db85Sdougm 			 * undo internally.
1269*6185db85Sdougm 			 */
1270*6185db85Sdougm 			xmlUnlinkNode(node);
1271*6185db85Sdougm 			xmlFreeNode(node);
1272*6185db85Sdougm 			node = NULL;
1273*6185db85Sdougm 		    }
1274*6185db85Sdougm 		} else {
1275*6185db85Sdougm 		    ret = SA_NO_MEMORY;
1276*6185db85Sdougm 		}
1277*6185db85Sdougm 	    } else {
1278*6185db85Sdougm 		ret = SA_INVALID_NAME;
1279*6185db85Sdougm 	    }
1280*6185db85Sdougm 	}
1281*6185db85Sdougm err:
1282*6185db85Sdougm 	if (error != NULL)
1283*6185db85Sdougm 	    *error = ret;
1284*6185db85Sdougm 	return ((sa_group_t)node);
1285*6185db85Sdougm }
1286*6185db85Sdougm 
1287*6185db85Sdougm /*
1288*6185db85Sdougm  * sa_remove_group(group)
1289*6185db85Sdougm  *
1290*6185db85Sdougm  * Remove the specified group. This deletes from the SMF repository.
1291*6185db85Sdougm  * All property groups and properties are removed.
1292*6185db85Sdougm  */
1293*6185db85Sdougm 
1294*6185db85Sdougm int
1295*6185db85Sdougm sa_remove_group(sa_group_t group)
1296*6185db85Sdougm {
1297*6185db85Sdougm 	char *name;
1298*6185db85Sdougm 	int ret = SA_OK;
1299*6185db85Sdougm 
1300*6185db85Sdougm 	name = sa_get_group_attr(group, "name");
1301*6185db85Sdougm 	if (name != NULL) {
1302*6185db85Sdougm 	    ret = sa_delete_instance(scf_handle, name);
1303*6185db85Sdougm 	    sa_free_attr_string(name);
1304*6185db85Sdougm 	}
1305*6185db85Sdougm 	xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
1306*6185db85Sdougm 	xmlFreeNode((xmlNodePtr)group);   /* now it is gone */
1307*6185db85Sdougm 	return (ret);
1308*6185db85Sdougm }
1309*6185db85Sdougm 
1310*6185db85Sdougm /*
1311*6185db85Sdougm  * sa_update_config()
1312*6185db85Sdougm  *
1313*6185db85Sdougm  * Used to update legacy files that need to be updated in bulk
1314*6185db85Sdougm  * Currently, this is a placeholder and will go away in a future
1315*6185db85Sdougm  * release.
1316*6185db85Sdougm  */
1317*6185db85Sdougm 
1318*6185db85Sdougm int
1319*6185db85Sdougm sa_update_config()
1320*6185db85Sdougm {
1321*6185db85Sdougm 	struct stat st;
1322*6185db85Sdougm 
1323*6185db85Sdougm 	/*
1324*6185db85Sdougm 	 * do legacy files first so we can tell when they change.
1325*6185db85Sdougm 	 * This will go away when we start updating individual records
1326*6185db85Sdougm 	 * rather than the whole file.
1327*6185db85Sdougm 	 */
1328*6185db85Sdougm 	update_legacy_config();
1329*6185db85Sdougm 	/* update legacy timestamp */
1330*6185db85Sdougm 	if (stat(SA_LEGACY_DFSTAB, &st) >= 0) {
1331*6185db85Sdougm 	    set_legacy_timestamp(sa_config_tree, SA_LEGACY_DFSTAB,
1332*6185db85Sdougm 					TSTAMP(st.st_ctim));
1333*6185db85Sdougm 	}
1334*6185db85Sdougm 	return (SA_OK);
1335*6185db85Sdougm }
1336*6185db85Sdougm 
1337*6185db85Sdougm /*
1338*6185db85Sdougm  * get_node_attr(node, tag)
1339*6185db85Sdougm  *
1340*6185db85Sdougm  * Get the speficied tag(attribute) if it exists on the node.  This is
1341*6185db85Sdougm  * used internally by a number of attribute oriented functions.
1342*6185db85Sdougm  */
1343*6185db85Sdougm 
1344*6185db85Sdougm static char *
1345*6185db85Sdougm get_node_attr(void *nodehdl, char *tag)
1346*6185db85Sdougm {
1347*6185db85Sdougm 	xmlNodePtr node = (xmlNodePtr)nodehdl;
1348*6185db85Sdougm 	xmlChar *name = NULL;
1349*6185db85Sdougm 
1350*6185db85Sdougm 	if (node != NULL) {
1351*6185db85Sdougm 		name = xmlGetProp(node, (xmlChar *)tag);
1352*6185db85Sdougm 	}
1353*6185db85Sdougm 	return ((char *)name);
1354*6185db85Sdougm }
1355*6185db85Sdougm 
1356*6185db85Sdougm /*
1357*6185db85Sdougm  * get_node_attr(node, tag)
1358*6185db85Sdougm  *
1359*6185db85Sdougm  * Set the speficied tag(attribute) to the specified value This is
1360*6185db85Sdougm  * used internally by a number of attribute oriented functions. It
1361*6185db85Sdougm  * doesn't update the repository, only the internal document state.
1362*6185db85Sdougm  */
1363*6185db85Sdougm 
1364*6185db85Sdougm void
1365*6185db85Sdougm set_node_attr(void *nodehdl, char *tag, char *value)
1366*6185db85Sdougm {
1367*6185db85Sdougm 	xmlNodePtr node = (xmlNodePtr)nodehdl;
1368*6185db85Sdougm 	if (node != NULL && tag != NULL) {
1369*6185db85Sdougm 		if (value != NULL) {
1370*6185db85Sdougm 			xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value);
1371*6185db85Sdougm 		} else {
1372*6185db85Sdougm 			xmlUnsetProp(node, (xmlChar *)tag);
1373*6185db85Sdougm 		}
1374*6185db85Sdougm 	}
1375*6185db85Sdougm }
1376*6185db85Sdougm 
1377*6185db85Sdougm /*
1378*6185db85Sdougm  * sa_get_group_attr(group, tag)
1379*6185db85Sdougm  *
1380*6185db85Sdougm  * Get the specied attribute, if defined, for the group.
1381*6185db85Sdougm  */
1382*6185db85Sdougm 
1383*6185db85Sdougm char *
1384*6185db85Sdougm sa_get_group_attr(sa_group_t group, char *tag)
1385*6185db85Sdougm {
1386*6185db85Sdougm 	return (get_node_attr((void *)group, tag));
1387*6185db85Sdougm }
1388*6185db85Sdougm 
1389*6185db85Sdougm /*
1390*6185db85Sdougm  * sa_set_group_attr(group, tag, value)
1391*6185db85Sdougm  *
1392*6185db85Sdougm  * set the specified tag/attribute on the group using value as its
1393*6185db85Sdougm  * value.
1394*6185db85Sdougm  *
1395*6185db85Sdougm  * This will result in setting the property in the SMF repository as
1396*6185db85Sdougm  * well as in the internal document.
1397*6185db85Sdougm  */
1398*6185db85Sdougm 
1399*6185db85Sdougm int
1400*6185db85Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value)
1401*6185db85Sdougm {
1402*6185db85Sdougm 	int ret;
1403*6185db85Sdougm 	char *groupname;
1404*6185db85Sdougm 
1405*6185db85Sdougm 	groupname = sa_get_group_attr(group, "name");
1406*6185db85Sdougm 	ret = sa_get_instance(scf_handle, groupname);
1407*6185db85Sdougm 	if (ret == SA_OK) {
1408*6185db85Sdougm 	    set_node_attr((void *)group, tag, value);
1409*6185db85Sdougm 	    ret = sa_start_transaction(scf_handle, "operation");
1410*6185db85Sdougm 	    if (ret == SA_OK) {
1411*6185db85Sdougm 		ret = sa_set_property(scf_handle, tag, value);
1412*6185db85Sdougm 		if (ret == SA_OK)
1413*6185db85Sdougm 		    (void) sa_end_transaction(scf_handle);
1414*6185db85Sdougm 		else {
1415*6185db85Sdougm 		    sa_abort_transaction(scf_handle);
1416*6185db85Sdougm 		}
1417*6185db85Sdougm 	    }
1418*6185db85Sdougm 	}
1419*6185db85Sdougm 	if (groupname != NULL)
1420*6185db85Sdougm 	    sa_free_attr_string(groupname);
1421*6185db85Sdougm 	return (ret);
1422*6185db85Sdougm }
1423*6185db85Sdougm 
1424*6185db85Sdougm /*
1425*6185db85Sdougm  * sa_get_share_attr(share, tag)
1426*6185db85Sdougm  *
1427*6185db85Sdougm  * Return the value of the tag/attribute set on the specified
1428*6185db85Sdougm  * share. Returns NULL if the tag doesn't exist.
1429*6185db85Sdougm  */
1430*6185db85Sdougm 
1431*6185db85Sdougm char *
1432*6185db85Sdougm sa_get_share_attr(sa_share_t share, char *tag)
1433*6185db85Sdougm {
1434*6185db85Sdougm 	return (get_node_attr((void *)share, tag));
1435*6185db85Sdougm }
1436*6185db85Sdougm 
1437*6185db85Sdougm /*
1438*6185db85Sdougm  * sa_get_resource(group, resource)
1439*6185db85Sdougm  *
1440*6185db85Sdougm  * Search all the shares in the speified group for a share with a
1441*6185db85Sdougm  * resource name matching the one specified.
1442*6185db85Sdougm  *
1443*6185db85Sdougm  * In the future, it may be advantageous to allow group to be NULL and
1444*6185db85Sdougm  * search all groups but that isn't needed at present.
1445*6185db85Sdougm  */
1446*6185db85Sdougm 
1447*6185db85Sdougm sa_share_t
1448*6185db85Sdougm sa_get_resource(sa_group_t group, char *resource)
1449*6185db85Sdougm {
1450*6185db85Sdougm 	sa_share_t share = NULL;
1451*6185db85Sdougm 	char *name = NULL;
1452*6185db85Sdougm 
1453*6185db85Sdougm 	if (resource != NULL) {
1454*6185db85Sdougm 	    for (share = sa_get_share(group, NULL); share != NULL;
1455*6185db85Sdougm 		share = sa_get_next_share(share)) {
1456*6185db85Sdougm 		name = sa_get_share_attr(share, "resource");
1457*6185db85Sdougm 		if (name != NULL) {
1458*6185db85Sdougm 		    if (strcmp(name, resource) == 0)
1459*6185db85Sdougm 			break;
1460*6185db85Sdougm 		    sa_free_attr_string(name);
1461*6185db85Sdougm 		    name = NULL;
1462*6185db85Sdougm 		}
1463*6185db85Sdougm 	    }
1464*6185db85Sdougm 	    if (name != NULL)
1465*6185db85Sdougm 		sa_free_attr_string(name);
1466*6185db85Sdougm 	}
1467*6185db85Sdougm 	return ((sa_share_t)share);
1468*6185db85Sdougm }
1469*6185db85Sdougm 
1470*6185db85Sdougm /*
1471*6185db85Sdougm  * _sa_set_share_description(share, description)
1472*6185db85Sdougm  *
1473*6185db85Sdougm  * Add a description tag with text contents to the specified share.
1474*6185db85Sdougm  * A separate XML tag is used rather than a property.
1475*6185db85Sdougm  */
1476*6185db85Sdougm 
1477*6185db85Sdougm xmlNodePtr
1478*6185db85Sdougm _sa_set_share_description(sa_share_t share, char *content)
1479*6185db85Sdougm {
1480*6185db85Sdougm 	xmlNodePtr node;
1481*6185db85Sdougm 	node = xmlNewChild((xmlNodePtr)share,
1482*6185db85Sdougm 			    NULL, (xmlChar *)"description", NULL);
1483*6185db85Sdougm 	xmlNodeSetContent(node, (xmlChar *)content);
1484*6185db85Sdougm 	return (node);
1485*6185db85Sdougm }
1486*6185db85Sdougm 
1487*6185db85Sdougm /*
1488*6185db85Sdougm  * sa_set_share_attr(share, tag, value)
1489*6185db85Sdougm  *
1490*6185db85Sdougm  * Set the share attribute specified by tag to the specified value. In
1491*6185db85Sdougm  * the case of "resource", enforce a no duplicates in a group rule. If
1492*6185db85Sdougm  * the share is not transient, commit the changes to the repository
1493*6185db85Sdougm  * else just update the share internally.
1494*6185db85Sdougm  */
1495*6185db85Sdougm 
1496*6185db85Sdougm int
1497*6185db85Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value)
1498*6185db85Sdougm {
1499*6185db85Sdougm 	sa_group_t group;
1500*6185db85Sdougm 	sa_share_t resource;
1501*6185db85Sdougm 	int ret = SA_OK;
1502*6185db85Sdougm 
1503*6185db85Sdougm 	group = sa_get_parent_group(share);
1504*6185db85Sdougm 
1505*6185db85Sdougm 	/*
1506*6185db85Sdougm 	 * There are some attributes that may have specific
1507*6185db85Sdougm 	 * restrictions on them. Initially, only "resource" has
1508*6185db85Sdougm 	 * special meaning that needs to be checked. Only one instance
1509*6185db85Sdougm 	 * of a resource name may exist within a group.
1510*6185db85Sdougm 	 */
1511*6185db85Sdougm 
1512*6185db85Sdougm 	if (strcmp(tag, "resource") == 0) {
1513*6185db85Sdougm 	    resource = sa_get_resource(group, value);
1514*6185db85Sdougm 	    if (resource != share && resource != NULL)
1515*6185db85Sdougm 		ret = SA_DUPLICATE_NAME;
1516*6185db85Sdougm 	}
1517*6185db85Sdougm 	if (ret == SA_OK) {
1518*6185db85Sdougm 	    set_node_attr((void *)share, tag, value);
1519*6185db85Sdougm 	    if (group != NULL) {
1520*6185db85Sdougm 		char *type;
1521*6185db85Sdougm 		/* we can probably optimize this some */
1522*6185db85Sdougm 		type = sa_get_share_attr(share, "type");
1523*6185db85Sdougm 		if (type == NULL || strcmp(type, "transient") != 0)
1524*6185db85Sdougm 		    ret = sa_commit_share(scf_handle, group, share);
1525*6185db85Sdougm 		if (type != NULL)
1526*6185db85Sdougm 		    sa_free_attr_string(type);
1527*6185db85Sdougm 	    }
1528*6185db85Sdougm 	}
1529*6185db85Sdougm 	return (ret);
1530*6185db85Sdougm }
1531*6185db85Sdougm 
1532*6185db85Sdougm /*
1533*6185db85Sdougm  * sa_get_property_attr(prop, tag)
1534*6185db85Sdougm  *
1535*6185db85Sdougm  * Get the value of the specified property attribute. Standard
1536*6185db85Sdougm  * attributes are "type" and "value".
1537*6185db85Sdougm  */
1538*6185db85Sdougm 
1539*6185db85Sdougm char *
1540*6185db85Sdougm sa_get_property_attr(sa_property_t prop, char *tag)
1541*6185db85Sdougm {
1542*6185db85Sdougm 	return (get_node_attr((void *)prop, tag));
1543*6185db85Sdougm }
1544*6185db85Sdougm 
1545*6185db85Sdougm /*
1546*6185db85Sdougm  * sa_get_optionset_attr(prop, tag)
1547*6185db85Sdougm  *
1548*6185db85Sdougm  * Get the value of the specified property attribute. Standard
1549*6185db85Sdougm  * attribute is "type".
1550*6185db85Sdougm  */
1551*6185db85Sdougm 
1552*6185db85Sdougm char *
1553*6185db85Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag)
1554*6185db85Sdougm {
1555*6185db85Sdougm 	return (get_node_attr((void *)optionset, tag));
1556*6185db85Sdougm 
1557*6185db85Sdougm }
1558*6185db85Sdougm 
1559*6185db85Sdougm /*
1560*6185db85Sdougm  * sa_set_optionset_attr(optionset, tag, value)
1561*6185db85Sdougm  *
1562*6185db85Sdougm  * Set the specified attribute(tag) to the specified value on the
1563*6185db85Sdougm  * optionset.
1564*6185db85Sdougm  */
1565*6185db85Sdougm 
1566*6185db85Sdougm void
1567*6185db85Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value)
1568*6185db85Sdougm {
1569*6185db85Sdougm 	set_node_attr((void *)optionset, tag, value);
1570*6185db85Sdougm }
1571*6185db85Sdougm 
1572*6185db85Sdougm /*
1573*6185db85Sdougm  * sa_free_attr_string(string)
1574*6185db85Sdougm  *
1575*6185db85Sdougm  * Free the string that was returned in one of the sa_get_*_attr()
1576*6185db85Sdougm  * functions.
1577*6185db85Sdougm  */
1578*6185db85Sdougm 
1579*6185db85Sdougm void
1580*6185db85Sdougm sa_free_attr_string(char *string)
1581*6185db85Sdougm {
1582*6185db85Sdougm 	xmlFree((xmlChar *)string);
1583*6185db85Sdougm }
1584*6185db85Sdougm 
1585*6185db85Sdougm /*
1586*6185db85Sdougm  * sa_get_optionset(group, proto)
1587*6185db85Sdougm  *
1588*6185db85Sdougm  * Return the optionset, if it exists, that is associated with the
1589*6185db85Sdougm  * specified protocol.
1590*6185db85Sdougm  */
1591*6185db85Sdougm 
1592*6185db85Sdougm sa_optionset_t
1593*6185db85Sdougm sa_get_optionset(void *group, char *proto)
1594*6185db85Sdougm {
1595*6185db85Sdougm 	xmlNodePtr node;
1596*6185db85Sdougm 	xmlChar *value = NULL;
1597*6185db85Sdougm 
1598*6185db85Sdougm 	for (node = ((xmlNodePtr)group)->children; node != NULL;
1599*6185db85Sdougm 		node = node->next) {
1600*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) {
1601*6185db85Sdougm 		    value = xmlGetProp(node, (xmlChar *)"type");
1602*6185db85Sdougm 		    if (proto != NULL) {
1603*6185db85Sdougm 			if (value != NULL &&
1604*6185db85Sdougm 			    xmlStrcmp(value, (xmlChar *)proto) == 0) {
1605*6185db85Sdougm 			    break;
1606*6185db85Sdougm 			}
1607*6185db85Sdougm 			if (value != NULL) {
1608*6185db85Sdougm 			    xmlFree(value);
1609*6185db85Sdougm 			    value = NULL;
1610*6185db85Sdougm 			}
1611*6185db85Sdougm 		    } else {
1612*6185db85Sdougm 			break;
1613*6185db85Sdougm 		    }
1614*6185db85Sdougm 		}
1615*6185db85Sdougm 	}
1616*6185db85Sdougm 	if (value != NULL)
1617*6185db85Sdougm 	    xmlFree(value);
1618*6185db85Sdougm 	return ((sa_optionset_t)node);
1619*6185db85Sdougm }
1620*6185db85Sdougm 
1621*6185db85Sdougm /*
1622*6185db85Sdougm  * sa_get_next_optionset(optionset)
1623*6185db85Sdougm  *
1624*6185db85Sdougm  * Return the next optionset in the group. NULL if this was the last.
1625*6185db85Sdougm  */
1626*6185db85Sdougm 
1627*6185db85Sdougm sa_optionset_t
1628*6185db85Sdougm sa_get_next_optionset(sa_optionset_t optionset)
1629*6185db85Sdougm {
1630*6185db85Sdougm 	xmlNodePtr node;
1631*6185db85Sdougm 
1632*6185db85Sdougm 	for (node = ((xmlNodePtr)optionset)->next; node != NULL;
1633*6185db85Sdougm 		node = node->next) {
1634*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) {
1635*6185db85Sdougm 			break;
1636*6185db85Sdougm 		}
1637*6185db85Sdougm 	}
1638*6185db85Sdougm 	return ((sa_optionset_t)node);
1639*6185db85Sdougm }
1640*6185db85Sdougm 
1641*6185db85Sdougm /*
1642*6185db85Sdougm  * sa_get_security(group, sectype, proto)
1643*6185db85Sdougm  *
1644*6185db85Sdougm  * Return the security optionset. The internal name is a hold over
1645*6185db85Sdougm  * from the implementation and will be changed before the API is
1646*6185db85Sdougm  * finalized. This is really a named optionset that can be negotiated
1647*6185db85Sdougm  * as a group of properties (like NFS security options).
1648*6185db85Sdougm  */
1649*6185db85Sdougm 
1650*6185db85Sdougm sa_security_t
1651*6185db85Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto)
1652*6185db85Sdougm {
1653*6185db85Sdougm 	xmlNodePtr node;
1654*6185db85Sdougm 	xmlChar *value = NULL;
1655*6185db85Sdougm 
1656*6185db85Sdougm 	for (node = ((xmlNodePtr)group)->children; node != NULL;
1657*6185db85Sdougm 		node = node->next) {
1658*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) {
1659*6185db85Sdougm 		if (proto != NULL) {
1660*6185db85Sdougm 		    value = xmlGetProp(node, (xmlChar *)"type");
1661*6185db85Sdougm 		    if (value == NULL ||
1662*6185db85Sdougm 			(value != NULL &&
1663*6185db85Sdougm 			xmlStrcmp(value, (xmlChar *)proto) != 0)) {
1664*6185db85Sdougm 			/* it doesn't match so continue */
1665*6185db85Sdougm 			xmlFree(value);
1666*6185db85Sdougm 			value = NULL;
1667*6185db85Sdougm 			continue;
1668*6185db85Sdougm 		    }
1669*6185db85Sdougm 		}
1670*6185db85Sdougm 		if (value != NULL) {
1671*6185db85Sdougm 		    xmlFree(value);
1672*6185db85Sdougm 		    value = NULL;
1673*6185db85Sdougm 		}
1674*6185db85Sdougm 		/* potential match */
1675*6185db85Sdougm 		if (sectype != NULL) {
1676*6185db85Sdougm 		    value = xmlGetProp(node, (xmlChar *)"sectype");
1677*6185db85Sdougm 		    if (value != NULL &&
1678*6185db85Sdougm 			xmlStrcmp(value, (xmlChar *)sectype) == 0) {
1679*6185db85Sdougm 			break;
1680*6185db85Sdougm 		    }
1681*6185db85Sdougm 		} else {
1682*6185db85Sdougm 		    break;
1683*6185db85Sdougm 		}
1684*6185db85Sdougm 	    }
1685*6185db85Sdougm 	    if (value != NULL) {
1686*6185db85Sdougm 		xmlFree(value);
1687*6185db85Sdougm 		value = NULL;
1688*6185db85Sdougm 	    }
1689*6185db85Sdougm 	}
1690*6185db85Sdougm 	if (value != NULL)
1691*6185db85Sdougm 	    xmlFree(value);
1692*6185db85Sdougm 	return ((sa_security_t)node);
1693*6185db85Sdougm }
1694*6185db85Sdougm 
1695*6185db85Sdougm /*
1696*6185db85Sdougm  * sa_get_next_security(security)
1697*6185db85Sdougm  *
1698*6185db85Sdougm  * Get the next security optionset if one exists.
1699*6185db85Sdougm  */
1700*6185db85Sdougm 
1701*6185db85Sdougm sa_security_t
1702*6185db85Sdougm sa_get_next_security(sa_security_t security)
1703*6185db85Sdougm {
1704*6185db85Sdougm 	xmlNodePtr node;
1705*6185db85Sdougm 
1706*6185db85Sdougm 	for (node = ((xmlNodePtr)security)->next; node != NULL;
1707*6185db85Sdougm 		node = node->next) {
1708*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) {
1709*6185db85Sdougm 			break;
1710*6185db85Sdougm 		}
1711*6185db85Sdougm 	}
1712*6185db85Sdougm 	return ((sa_security_t)node);
1713*6185db85Sdougm }
1714*6185db85Sdougm 
1715*6185db85Sdougm /*
1716*6185db85Sdougm  * sa_get_property(optionset, prop)
1717*6185db85Sdougm  *
1718*6185db85Sdougm  * Get the property object with the name specified in prop from the
1719*6185db85Sdougm  * optionset.
1720*6185db85Sdougm  */
1721*6185db85Sdougm 
1722*6185db85Sdougm sa_property_t
1723*6185db85Sdougm sa_get_property(sa_optionset_t optionset, char *prop)
1724*6185db85Sdougm {
1725*6185db85Sdougm 	xmlNodePtr node = (xmlNodePtr)optionset;
1726*6185db85Sdougm 	xmlChar *value = NULL;
1727*6185db85Sdougm 
1728*6185db85Sdougm 	if (optionset == NULL)
1729*6185db85Sdougm 	    return (NULL);
1730*6185db85Sdougm 
1731*6185db85Sdougm 	for (node = node->children; node != NULL;
1732*6185db85Sdougm 		node = node->next) {
1733*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
1734*6185db85Sdougm 		if (prop == NULL)
1735*6185db85Sdougm 		    break;
1736*6185db85Sdougm 		value = xmlGetProp(node, (xmlChar *)"type");
1737*6185db85Sdougm 		if (value != NULL && xmlStrcmp(value, (xmlChar *)prop) == 0) {
1738*6185db85Sdougm 		    break;
1739*6185db85Sdougm 		}
1740*6185db85Sdougm 		if (value != NULL) {
1741*6185db85Sdougm 		    xmlFree(value);
1742*6185db85Sdougm 		    value = NULL;
1743*6185db85Sdougm 		}
1744*6185db85Sdougm 	    }
1745*6185db85Sdougm 	}
1746*6185db85Sdougm 	if (value != NULL)
1747*6185db85Sdougm 		xmlFree(value);
1748*6185db85Sdougm 	if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) {
1749*6185db85Sdougm 	    /* avoid a non option node -- it is possible to be a text node */
1750*6185db85Sdougm 	    node = NULL;
1751*6185db85Sdougm 	}
1752*6185db85Sdougm 	return ((sa_property_t)node);
1753*6185db85Sdougm }
1754*6185db85Sdougm 
1755*6185db85Sdougm /*
1756*6185db85Sdougm  * sa_get_next_property(property)
1757*6185db85Sdougm  *
1758*6185db85Sdougm  * Get the next property following the specified property. NULL if
1759*6185db85Sdougm  * this was the last.
1760*6185db85Sdougm  */
1761*6185db85Sdougm 
1762*6185db85Sdougm sa_property_t
1763*6185db85Sdougm sa_get_next_property(sa_property_t property)
1764*6185db85Sdougm {
1765*6185db85Sdougm 	xmlNodePtr node;
1766*6185db85Sdougm 
1767*6185db85Sdougm 	for (node = ((xmlNodePtr)property)->next; node != NULL;
1768*6185db85Sdougm 		node = node->next) {
1769*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
1770*6185db85Sdougm 			break;
1771*6185db85Sdougm 		}
1772*6185db85Sdougm 	}
1773*6185db85Sdougm 	return ((sa_property_t)node);
1774*6185db85Sdougm }
1775*6185db85Sdougm 
1776*6185db85Sdougm /*
1777*6185db85Sdougm  * sa_set_share_description(share, content)
1778*6185db85Sdougm  *
1779*6185db85Sdougm  * Set the description of share to content.
1780*6185db85Sdougm  */
1781*6185db85Sdougm 
1782*6185db85Sdougm int
1783*6185db85Sdougm sa_set_share_description(sa_share_t share, char *content)
1784*6185db85Sdougm {
1785*6185db85Sdougm 	xmlNodePtr node;
1786*6185db85Sdougm 	sa_group_t group;
1787*6185db85Sdougm 	int ret = SA_OK;
1788*6185db85Sdougm 
1789*6185db85Sdougm 	for (node = ((xmlNodePtr)share)->children; node != NULL;
1790*6185db85Sdougm 		node = node->next) {
1791*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
1792*6185db85Sdougm 			break;
1793*6185db85Sdougm 		}
1794*6185db85Sdougm 	}
1795*6185db85Sdougm 	group = sa_get_parent_group(share);
1796*6185db85Sdougm 	/* no existing description but want to add */
1797*6185db85Sdougm 	if (node == NULL && content != NULL) {
1798*6185db85Sdougm 		/* add a description */
1799*6185db85Sdougm 	    node = _sa_set_share_description(share, content);
1800*6185db85Sdougm 	} else if (node != NULL && content != NULL) {
1801*6185db85Sdougm 		/* update a description */
1802*6185db85Sdougm 		xmlNodeSetContent(node, (xmlChar *)content);
1803*6185db85Sdougm 	} else if (node != NULL && content == NULL) {
1804*6185db85Sdougm 		/* remove an existing description */
1805*6185db85Sdougm 		xmlUnlinkNode(node);
1806*6185db85Sdougm 		xmlFreeNode(node);
1807*6185db85Sdougm 	}
1808*6185db85Sdougm 	if (group != NULL && is_persistent((sa_group_t)share))
1809*6185db85Sdougm 	    ret = sa_commit_share(scf_handle, group, share);
1810*6185db85Sdougm 	return (ret);
1811*6185db85Sdougm }
1812*6185db85Sdougm 
1813*6185db85Sdougm /*
1814*6185db85Sdougm  * fixproblemchars(string)
1815*6185db85Sdougm  *
1816*6185db85Sdougm  * don't want any newline or tab characters in the text since these
1817*6185db85Sdougm  * could break display of data and legacy file formats.
1818*6185db85Sdougm  */
1819*6185db85Sdougm static void
1820*6185db85Sdougm fixproblemchars(char *str)
1821*6185db85Sdougm {
1822*6185db85Sdougm 	int c;
1823*6185db85Sdougm 	for (c = *str; c != '\0'; c = *++str) {
1824*6185db85Sdougm 	    if (c == '\t' || c == '\n')
1825*6185db85Sdougm 		*str = ' ';
1826*6185db85Sdougm 	    else if (c == '"')
1827*6185db85Sdougm 		*str = '\'';
1828*6185db85Sdougm 	}
1829*6185db85Sdougm }
1830*6185db85Sdougm 
1831*6185db85Sdougm /*
1832*6185db85Sdougm  * sa_get_share_description(share)
1833*6185db85Sdougm  *
1834*6185db85Sdougm  * Return the description text for the specified share if it
1835*6185db85Sdougm  * exists. NULL if no description exists.
1836*6185db85Sdougm  */
1837*6185db85Sdougm 
1838*6185db85Sdougm char *
1839*6185db85Sdougm sa_get_share_description(sa_share_t share)
1840*6185db85Sdougm {
1841*6185db85Sdougm 	xmlChar *description = NULL;
1842*6185db85Sdougm 	xmlNodePtr node;
1843*6185db85Sdougm 
1844*6185db85Sdougm 	for (node = ((xmlNodePtr)share)->children; node != NULL;
1845*6185db85Sdougm 		node = node->next) {
1846*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
1847*6185db85Sdougm 		break;
1848*6185db85Sdougm 	    }
1849*6185db85Sdougm 	}
1850*6185db85Sdougm 	if (node != NULL) {
1851*6185db85Sdougm 	    description = xmlNodeGetContent((xmlNodePtr)share);
1852*6185db85Sdougm 	    fixproblemchars((char *)description);
1853*6185db85Sdougm 	}
1854*6185db85Sdougm 	return ((char *)description);
1855*6185db85Sdougm }
1856*6185db85Sdougm 
1857*6185db85Sdougm /*
1858*6185db85Sdougm  * sa_free(share_description(description)
1859*6185db85Sdougm  *
1860*6185db85Sdougm  * Free the description string.
1861*6185db85Sdougm  */
1862*6185db85Sdougm 
1863*6185db85Sdougm void
1864*6185db85Sdougm sa_free_share_description(char *description)
1865*6185db85Sdougm {
1866*6185db85Sdougm 	xmlFree((xmlChar *)description);
1867*6185db85Sdougm }
1868*6185db85Sdougm 
1869*6185db85Sdougm /*
1870*6185db85Sdougm  * sa_create_optionset(group, proto)
1871*6185db85Sdougm  *
1872*6185db85Sdougm  * Create an optionset for the specified protocol in the specied
1873*6185db85Sdougm  * group. This is manifested as a property group within SMF.
1874*6185db85Sdougm  */
1875*6185db85Sdougm 
1876*6185db85Sdougm sa_optionset_t
1877*6185db85Sdougm sa_create_optionset(sa_group_t group, char *proto)
1878*6185db85Sdougm {
1879*6185db85Sdougm 	sa_optionset_t optionset;
1880*6185db85Sdougm 	sa_group_t parent = group;
1881*6185db85Sdougm 
1882*6185db85Sdougm 	optionset = sa_get_optionset(group, proto);
1883*6185db85Sdougm 	if (optionset != NULL) {
1884*6185db85Sdougm 		/* can't have a duplicate protocol */
1885*6185db85Sdougm 	    optionset = NULL;
1886*6185db85Sdougm 	} else {
1887*6185db85Sdougm 	    optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group,
1888*6185db85Sdougm 						    NULL,
1889*6185db85Sdougm 						    (xmlChar *)"optionset",
1890*6185db85Sdougm 						    NULL);
1891*6185db85Sdougm 		/*
1892*6185db85Sdougm 		 * only put to repository if on a group and we were
1893*6185db85Sdougm 		 * able to create an optionset.
1894*6185db85Sdougm 		 */
1895*6185db85Sdougm 	    if (optionset != NULL) {
1896*6185db85Sdougm 		char oname[256];
1897*6185db85Sdougm 		char *groupname;
1898*6185db85Sdougm 		char *id = NULL;
1899*6185db85Sdougm 
1900*6185db85Sdougm 		if (sa_is_share(group))
1901*6185db85Sdougm 		    parent = sa_get_parent_group((sa_share_t)group);
1902*6185db85Sdougm 
1903*6185db85Sdougm 		sa_set_optionset_attr(optionset, "type", proto);
1904*6185db85Sdougm 
1905*6185db85Sdougm 		if (sa_is_share(group)) {
1906*6185db85Sdougm 			id = sa_get_share_attr((sa_share_t)group, "id");
1907*6185db85Sdougm 		}
1908*6185db85Sdougm 		(void) sa_optionset_name(optionset, oname,
1909*6185db85Sdougm 					sizeof (oname), id);
1910*6185db85Sdougm 		groupname = sa_get_group_attr(parent, "name");
1911*6185db85Sdougm 		if (groupname != NULL && is_persistent(group)) {
1912*6185db85Sdougm 			(void) sa_get_instance(scf_handle, groupname);
1913*6185db85Sdougm 			sa_free_attr_string(groupname);
1914*6185db85Sdougm 			(void) sa_create_pgroup(scf_handle, oname);
1915*6185db85Sdougm 		}
1916*6185db85Sdougm 		if (id != NULL)
1917*6185db85Sdougm 		    sa_free_attr_string(id);
1918*6185db85Sdougm 	    }
1919*6185db85Sdougm 	}
1920*6185db85Sdougm 	return (optionset);
1921*6185db85Sdougm }
1922*6185db85Sdougm 
1923*6185db85Sdougm /*
1924*6185db85Sdougm  * sa_get_property_parent(property)
1925*6185db85Sdougm  *
1926*6185db85Sdougm  * Given a property, return the object it is a property of. This will
1927*6185db85Sdougm  * be an optionset of some type.
1928*6185db85Sdougm  */
1929*6185db85Sdougm 
1930*6185db85Sdougm static sa_optionset_t
1931*6185db85Sdougm sa_get_property_parent(sa_property_t property)
1932*6185db85Sdougm {
1933*6185db85Sdougm 	xmlNodePtr node = NULL;
1934*6185db85Sdougm 
1935*6185db85Sdougm 	if (property != NULL) {
1936*6185db85Sdougm 	    node = ((xmlNodePtr)property)->parent;
1937*6185db85Sdougm 	}
1938*6185db85Sdougm 	return ((sa_optionset_t)node);
1939*6185db85Sdougm }
1940*6185db85Sdougm 
1941*6185db85Sdougm /*
1942*6185db85Sdougm  * sa_get_optionset_parent(optionset)
1943*6185db85Sdougm  *
1944*6185db85Sdougm  * Return the parent of the specified optionset. This could be a group
1945*6185db85Sdougm  * or a share.
1946*6185db85Sdougm  */
1947*6185db85Sdougm 
1948*6185db85Sdougm static sa_group_t
1949*6185db85Sdougm sa_get_optionset_parent(sa_optionset_t optionset)
1950*6185db85Sdougm {
1951*6185db85Sdougm 	xmlNodePtr node = NULL;
1952*6185db85Sdougm 
1953*6185db85Sdougm 	if (optionset != NULL) {
1954*6185db85Sdougm 	    node = ((xmlNodePtr)optionset)->parent;
1955*6185db85Sdougm 	}
1956*6185db85Sdougm 	return ((sa_group_t)node);
1957*6185db85Sdougm }
1958*6185db85Sdougm 
1959*6185db85Sdougm /*
1960*6185db85Sdougm  * zfs_needs_update(share)
1961*6185db85Sdougm  *
1962*6185db85Sdougm  * In order to avoid making multiple updates to a ZFS share when
1963*6185db85Sdougm  * setting properties, the share attribute "changed" will be set to
1964*6185db85Sdougm  * true when a property is added or modifed.  When done adding
1965*6185db85Sdougm  * properties, we can then detect that an update is needed.  We then
1966*6185db85Sdougm  * clear the state here to detect additional changes.
1967*6185db85Sdougm  */
1968*6185db85Sdougm 
1969*6185db85Sdougm static int
1970*6185db85Sdougm zfs_needs_update(sa_share_t share)
1971*6185db85Sdougm {
1972*6185db85Sdougm 	char *attr;
1973*6185db85Sdougm 	int result = 0;
1974*6185db85Sdougm 
1975*6185db85Sdougm 	attr = sa_get_share_attr(share, "changed");
1976*6185db85Sdougm 	if (attr != NULL) {
1977*6185db85Sdougm 	    sa_free_attr_string(attr);
1978*6185db85Sdougm 		result = 1;
1979*6185db85Sdougm 	}
1980*6185db85Sdougm 	set_node_attr((void *)share, "changed", NULL);
1981*6185db85Sdougm 	return (result);
1982*6185db85Sdougm }
1983*6185db85Sdougm 
1984*6185db85Sdougm /*
1985*6185db85Sdougm  * zfs_set_update(share)
1986*6185db85Sdougm  *
1987*6185db85Sdougm  * Set the changed attribute of the share to true.
1988*6185db85Sdougm  */
1989*6185db85Sdougm 
1990*6185db85Sdougm static void
1991*6185db85Sdougm zfs_set_update(sa_share_t share)
1992*6185db85Sdougm {
1993*6185db85Sdougm 	set_node_attr((void *)share, "changed", "true");
1994*6185db85Sdougm }
1995*6185db85Sdougm 
1996*6185db85Sdougm /*
1997*6185db85Sdougm  * sa_commit_properties(optionset, clear)
1998*6185db85Sdougm  *
1999*6185db85Sdougm  * Check if SMF or ZFS config and either update or abort the pending
2000*6185db85Sdougm  * changes.
2001*6185db85Sdougm  */
2002*6185db85Sdougm 
2003*6185db85Sdougm int
2004*6185db85Sdougm sa_commit_properties(sa_optionset_t optionset, int clear)
2005*6185db85Sdougm {
2006*6185db85Sdougm 	sa_group_t group;
2007*6185db85Sdougm 	sa_group_t parent;
2008*6185db85Sdougm 	int zfs = 0;
2009*6185db85Sdougm 	int needsupdate = 0;
2010*6185db85Sdougm 	int ret = SA_OK;
2011*6185db85Sdougm 
2012*6185db85Sdougm 	group = sa_get_optionset_parent(optionset);
2013*6185db85Sdougm 	if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) {
2014*6185db85Sdougm 	    /* only update ZFS if on a share */
2015*6185db85Sdougm 	    parent = sa_get_parent_group(group);
2016*6185db85Sdougm 	    zfs++;
2017*6185db85Sdougm 	    if (parent != NULL && is_zfs_group(parent)) {
2018*6185db85Sdougm 		needsupdate = zfs_needs_update(group);
2019*6185db85Sdougm 	    } else {
2020*6185db85Sdougm 		zfs = 0;
2021*6185db85Sdougm 	    }
2022*6185db85Sdougm 	}
2023*6185db85Sdougm 	if (zfs) {
2024*6185db85Sdougm 	    if (!clear && needsupdate)
2025*6185db85Sdougm 		ret = sa_zfs_update((sa_share_t)group);
2026*6185db85Sdougm 	} else {
2027*6185db85Sdougm 	    if (clear)
2028*6185db85Sdougm 		(void) sa_abort_transaction(scf_handle);
2029*6185db85Sdougm 	    else
2030*6185db85Sdougm 		ret = sa_end_transaction(scf_handle);
2031*6185db85Sdougm 	}
2032*6185db85Sdougm 	return (ret);
2033*6185db85Sdougm }
2034*6185db85Sdougm 
2035*6185db85Sdougm /*
2036*6185db85Sdougm  * sa_destroy_optionset(optionset)
2037*6185db85Sdougm  *
2038*6185db85Sdougm  * Remove the optionset from its group. Update the repostory to
2039*6185db85Sdougm  * reflect this change.
2040*6185db85Sdougm  */
2041*6185db85Sdougm 
2042*6185db85Sdougm int
2043*6185db85Sdougm sa_destroy_optionset(sa_optionset_t optionset)
2044*6185db85Sdougm {
2045*6185db85Sdougm 	char name[256];
2046*6185db85Sdougm 	int len;
2047*6185db85Sdougm 	int ret;
2048*6185db85Sdougm 	char *id = NULL;
2049*6185db85Sdougm 	sa_group_t group;
2050*6185db85Sdougm 	int ispersist = 1;
2051*6185db85Sdougm 
2052*6185db85Sdougm 	/* now delete the prop group */
2053*6185db85Sdougm 	group = sa_get_optionset_parent(optionset);
2054*6185db85Sdougm 	if (group != NULL && sa_is_share(group)) {
2055*6185db85Sdougm 	    ispersist = is_persistent(group);
2056*6185db85Sdougm 	    id = sa_get_share_attr((sa_share_t)group, "id");
2057*6185db85Sdougm 	}
2058*6185db85Sdougm 	if (ispersist) {
2059*6185db85Sdougm 	    len = sa_optionset_name(optionset, name, sizeof (name), id);
2060*6185db85Sdougm 	    if (len > 0) {
2061*6185db85Sdougm 		ret = sa_delete_pgroup(scf_handle, name);
2062*6185db85Sdougm 	    }
2063*6185db85Sdougm 	}
2064*6185db85Sdougm 	xmlUnlinkNode((xmlNodePtr)optionset);
2065*6185db85Sdougm 	xmlFreeNode((xmlNodePtr)optionset);
2066*6185db85Sdougm 	if (id != NULL)
2067*6185db85Sdougm 	    sa_free_attr_string(id);
2068*6185db85Sdougm 	return (ret);
2069*6185db85Sdougm }
2070*6185db85Sdougm 
2071*6185db85Sdougm /* private to the implementation */
2072*6185db85Sdougm int
2073*6185db85Sdougm _sa_remove_optionset(sa_optionset_t optionset)
2074*6185db85Sdougm {
2075*6185db85Sdougm 	int ret = SA_OK;
2076*6185db85Sdougm 
2077*6185db85Sdougm 	xmlUnlinkNode((xmlNodePtr)optionset);
2078*6185db85Sdougm 	xmlFreeNode((xmlNodePtr)optionset);
2079*6185db85Sdougm 	return (ret);
2080*6185db85Sdougm }
2081*6185db85Sdougm 
2082*6185db85Sdougm /*
2083*6185db85Sdougm  * sa_create_security(group, sectype, proto)
2084*6185db85Sdougm  *
2085*6185db85Sdougm  * Create a security optionset (one that has a type name and a
2086*6185db85Sdougm  * proto). Security is left over from a pure NFS implementation. The
2087*6185db85Sdougm  * naming will change in the future when the API is released.
2088*6185db85Sdougm  */
2089*6185db85Sdougm sa_security_t
2090*6185db85Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto)
2091*6185db85Sdougm {
2092*6185db85Sdougm 	sa_security_t security;
2093*6185db85Sdougm 	char *id = NULL;
2094*6185db85Sdougm 	sa_group_t parent;
2095*6185db85Sdougm 	char *groupname = NULL;
2096*6185db85Sdougm 
2097*6185db85Sdougm 	if (group != NULL && sa_is_share(group)) {
2098*6185db85Sdougm 	    id = sa_get_share_attr((sa_share_t)group, "id");
2099*6185db85Sdougm 	    parent = sa_get_parent_group(group);
2100*6185db85Sdougm 	    if (parent != NULL)
2101*6185db85Sdougm 		groupname = sa_get_group_attr(parent, "name");
2102*6185db85Sdougm 	} else if (group != NULL) {
2103*6185db85Sdougm 	    groupname = sa_get_group_attr(group, "name");
2104*6185db85Sdougm 	}
2105*6185db85Sdougm 
2106*6185db85Sdougm 	security = sa_get_security(group, sectype, proto);
2107*6185db85Sdougm 	if (security != NULL) {
2108*6185db85Sdougm 		/* can't have a duplicate security option */
2109*6185db85Sdougm 		security = NULL;
2110*6185db85Sdougm 	} else {
2111*6185db85Sdougm 		security = (sa_security_t)xmlNewChild((xmlNodePtr)group,
2112*6185db85Sdougm 							NULL,
2113*6185db85Sdougm 							(xmlChar *)"security",
2114*6185db85Sdougm 							NULL);
2115*6185db85Sdougm 		if (security != NULL) {
2116*6185db85Sdougm 			char oname[256];
2117*6185db85Sdougm 			sa_set_security_attr(security, "type", proto);
2118*6185db85Sdougm 
2119*6185db85Sdougm 			sa_set_security_attr(security, "sectype", sectype);
2120*6185db85Sdougm 			(void) sa_security_name(security, oname,
2121*6185db85Sdougm 						sizeof (oname), id);
2122*6185db85Sdougm 			if (groupname != NULL && is_persistent(group)) {
2123*6185db85Sdougm 			    (void) sa_get_instance(scf_handle, groupname);
2124*6185db85Sdougm 			    (void) sa_create_pgroup(scf_handle, oname);
2125*6185db85Sdougm 			}
2126*6185db85Sdougm 		}
2127*6185db85Sdougm 	}
2128*6185db85Sdougm 	if (groupname != NULL)
2129*6185db85Sdougm 	    sa_free_attr_string(groupname);
2130*6185db85Sdougm 	return (security);
2131*6185db85Sdougm }
2132*6185db85Sdougm 
2133*6185db85Sdougm /*
2134*6185db85Sdougm  * sa_destroy_security(security)
2135*6185db85Sdougm  *
2136*6185db85Sdougm  * Remove the specified optionset from the document and the
2137*6185db85Sdougm  * configuration.
2138*6185db85Sdougm  */
2139*6185db85Sdougm 
2140*6185db85Sdougm int
2141*6185db85Sdougm sa_destroy_security(sa_security_t security)
2142*6185db85Sdougm {
2143*6185db85Sdougm 	char name[256];
2144*6185db85Sdougm 	int len;
2145*6185db85Sdougm 	int ret = SA_OK;
2146*6185db85Sdougm 	char *id = NULL;
2147*6185db85Sdougm 	sa_group_t group;
2148*6185db85Sdougm 	int iszfs = 0;
2149*6185db85Sdougm 	int ispersist = 1;
2150*6185db85Sdougm 
2151*6185db85Sdougm 	group = sa_get_optionset_parent(security);
2152*6185db85Sdougm 
2153*6185db85Sdougm 	if (group != NULL)
2154*6185db85Sdougm 	    iszfs = sa_group_is_zfs(group);
2155*6185db85Sdougm 
2156*6185db85Sdougm 	if (group != NULL && !iszfs) {
2157*6185db85Sdougm 	    if (sa_is_share(group))
2158*6185db85Sdougm 		ispersist = is_persistent(group);
2159*6185db85Sdougm 	    id = sa_get_share_attr((sa_share_t)group, "id");
2160*6185db85Sdougm 	}
2161*6185db85Sdougm 	if (ispersist) {
2162*6185db85Sdougm 	    len = sa_security_name(security, name, sizeof (name), id);
2163*6185db85Sdougm 	    if (!iszfs && len > 0) {
2164*6185db85Sdougm 		ret = sa_delete_pgroup(scf_handle, name);
2165*6185db85Sdougm 	    }
2166*6185db85Sdougm 	}
2167*6185db85Sdougm 	xmlUnlinkNode((xmlNodePtr)security);
2168*6185db85Sdougm 	xmlFreeNode((xmlNodePtr)security);
2169*6185db85Sdougm 	if (iszfs) {
2170*6185db85Sdougm 	    ret = sa_zfs_update(group);
2171*6185db85Sdougm 	}
2172*6185db85Sdougm 	if (id != NULL)
2173*6185db85Sdougm 	    sa_free_attr_string(id);
2174*6185db85Sdougm 	return (ret);
2175*6185db85Sdougm }
2176*6185db85Sdougm 
2177*6185db85Sdougm /*
2178*6185db85Sdougm  * sa_get_security_attr(optionset, tag)
2179*6185db85Sdougm  *
2180*6185db85Sdougm  * Return the specified attribute value from the optionset.
2181*6185db85Sdougm  */
2182*6185db85Sdougm 
2183*6185db85Sdougm char *
2184*6185db85Sdougm sa_get_security_attr(sa_property_t optionset, char *tag)
2185*6185db85Sdougm {
2186*6185db85Sdougm 	return (get_node_attr((void *)optionset, tag));
2187*6185db85Sdougm 
2188*6185db85Sdougm }
2189*6185db85Sdougm 
2190*6185db85Sdougm /*
2191*6185db85Sdougm  * sa_set_security_attr(optionset, tag, value)
2192*6185db85Sdougm  *
2193*6185db85Sdougm  * Set the optioset attribute specied by tag to the specified value.
2194*6185db85Sdougm  */
2195*6185db85Sdougm 
2196*6185db85Sdougm void
2197*6185db85Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value)
2198*6185db85Sdougm {
2199*6185db85Sdougm 	set_node_attr((void *)optionset, tag, value);
2200*6185db85Sdougm }
2201*6185db85Sdougm 
2202*6185db85Sdougm /*
2203*6185db85Sdougm  * is_nodetype(node, type)
2204*6185db85Sdougm  *
2205*6185db85Sdougm  * Check to see if node is of the type specified.
2206*6185db85Sdougm  */
2207*6185db85Sdougm 
2208*6185db85Sdougm static int
2209*6185db85Sdougm is_nodetype(void *node, char *type)
2210*6185db85Sdougm {
2211*6185db85Sdougm 	return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0);
2212*6185db85Sdougm }
2213*6185db85Sdougm 
2214*6185db85Sdougm /*
2215*6185db85Sdougm  * sa_set_prop_by_prop(optionset, group, prop, type)
2216*6185db85Sdougm  *
2217*6185db85Sdougm  * Add/remove/update the specified property prop into the optionset or
2218*6185db85Sdougm  * share. If a share, sort out which property group based on GUID. In
2219*6185db85Sdougm  * all cases, the appropriate transaction is set (or ZFS share is
2220*6185db85Sdougm  * marked as needing an update)
2221*6185db85Sdougm  */
2222*6185db85Sdougm 
2223*6185db85Sdougm #define	SA_PROP_OP_REMOVE	1
2224*6185db85Sdougm #define	SA_PROP_OP_ADD		2
2225*6185db85Sdougm #define	SA_PROP_OP_UPDATE	3
2226*6185db85Sdougm static int
2227*6185db85Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
2228*6185db85Sdougm 			sa_property_t prop, int type)
2229*6185db85Sdougm {
2230*6185db85Sdougm 	char *name;
2231*6185db85Sdougm 	char *valstr;
2232*6185db85Sdougm 	int ret = SA_OK;
2233*6185db85Sdougm 	scf_transaction_entry_t *entry;
2234*6185db85Sdougm 	scf_value_t *value;
2235*6185db85Sdougm 	int opttype; /* 1 == optionset, 0 == security */
2236*6185db85Sdougm 	char *id = NULL;
2237*6185db85Sdougm 	int iszfs = 0;
2238*6185db85Sdougm 	int isshare = 0;
2239*6185db85Sdougm 	sa_group_t parent = NULL;
2240*6185db85Sdougm 
2241*6185db85Sdougm 	if (!is_persistent(group)) {
2242*6185db85Sdougm 		/*
2243*6185db85Sdougm 		 * if the group/share is not persistent we don't need
2244*6185db85Sdougm 		 * to do anything here
2245*6185db85Sdougm 		 */
2246*6185db85Sdougm 	    return (SA_OK);
2247*6185db85Sdougm 	}
2248*6185db85Sdougm 	name = sa_get_property_attr(prop, "type");
2249*6185db85Sdougm 	valstr = sa_get_property_attr(prop, "value");
2250*6185db85Sdougm 	entry = scf_entry_create(scf_handle->handle);
2251*6185db85Sdougm 	opttype = is_nodetype((void *)optionset, "optionset");
2252*6185db85Sdougm 
2253*6185db85Sdougm 	if (valstr != NULL && entry != NULL) {
2254*6185db85Sdougm 	    if (sa_is_share(group)) {
2255*6185db85Sdougm 		isshare = 1;
2256*6185db85Sdougm 		parent = sa_get_parent_group(group);
2257*6185db85Sdougm 		if (parent != NULL) {
2258*6185db85Sdougm 		    iszfs = is_zfs_group(parent);
2259*6185db85Sdougm 		}
2260*6185db85Sdougm 	    } else {
2261*6185db85Sdougm 		iszfs = is_zfs_group(group);
2262*6185db85Sdougm 	    }
2263*6185db85Sdougm 	    if (!iszfs) {
2264*6185db85Sdougm 		if (scf_handle->trans == NULL) {
2265*6185db85Sdougm 		    char oname[256];
2266*6185db85Sdougm 		    char *groupname = NULL;
2267*6185db85Sdougm 		    if (isshare) {
2268*6185db85Sdougm 			if (parent != NULL) {
2269*6185db85Sdougm 			    groupname = sa_get_group_attr(parent, "name");
2270*6185db85Sdougm 			}
2271*6185db85Sdougm 			id = sa_get_share_attr((sa_share_t)group, "id");
2272*6185db85Sdougm 		    } else {
2273*6185db85Sdougm 			groupname = sa_get_group_attr(group, "name");
2274*6185db85Sdougm 		    }
2275*6185db85Sdougm 		    if (groupname != NULL) {
2276*6185db85Sdougm 			ret = sa_get_instance(scf_handle, groupname);
2277*6185db85Sdougm 			sa_free_attr_string(groupname);
2278*6185db85Sdougm 		    }
2279*6185db85Sdougm 		    if (opttype)
2280*6185db85Sdougm 			(void) sa_optionset_name(optionset, oname,
2281*6185db85Sdougm 							sizeof (oname), id);
2282*6185db85Sdougm 		    else
2283*6185db85Sdougm 			(void) sa_security_name(optionset, oname,
2284*6185db85Sdougm 							sizeof (oname), id);
2285*6185db85Sdougm 		    ret = sa_start_transaction(scf_handle, oname);
2286*6185db85Sdougm 		}
2287*6185db85Sdougm 		if (ret == SA_OK) {
2288*6185db85Sdougm 		    switch (type) {
2289*6185db85Sdougm 		    case SA_PROP_OP_REMOVE:
2290*6185db85Sdougm 			ret = scf_transaction_property_delete(scf_handle->trans,
2291*6185db85Sdougm 								entry,
2292*6185db85Sdougm 								name);
2293*6185db85Sdougm 			break;
2294*6185db85Sdougm 		    case SA_PROP_OP_ADD:
2295*6185db85Sdougm 		    case SA_PROP_OP_UPDATE:
2296*6185db85Sdougm 			value = scf_value_create(scf_handle->handle);
2297*6185db85Sdougm 			if (value != NULL) {
2298*6185db85Sdougm 			    if (type == SA_PROP_OP_ADD)
2299*6185db85Sdougm 				ret = scf_transaction_property_new(
2300*6185db85Sdougm 							    scf_handle->trans,
2301*6185db85Sdougm 							    entry,
2302*6185db85Sdougm 							    name,
2303*6185db85Sdougm 							    SCF_TYPE_ASTRING);
2304*6185db85Sdougm 			    else
2305*6185db85Sdougm 				ret = scf_transaction_property_change(
2306*6185db85Sdougm 							    scf_handle->trans,
2307*6185db85Sdougm 							    entry,
2308*6185db85Sdougm 							    name,
2309*6185db85Sdougm 							    SCF_TYPE_ASTRING);
2310*6185db85Sdougm 			    if (ret == 0) {
2311*6185db85Sdougm 				ret = scf_value_set_astring(value, valstr);
2312*6185db85Sdougm 				if (ret == 0)
2313*6185db85Sdougm 				    ret = scf_entry_add_value(entry, value);
2314*6185db85Sdougm 				if (ret != 0) {
2315*6185db85Sdougm 				    scf_value_destroy(value);
2316*6185db85Sdougm 				    ret = SA_SYSTEM_ERR;
2317*6185db85Sdougm 				}
2318*6185db85Sdougm 			    } else {
2319*6185db85Sdougm 				scf_entry_destroy(entry);
2320*6185db85Sdougm 				ret = SA_SYSTEM_ERR;
2321*6185db85Sdougm 			    }
2322*6185db85Sdougm 			    break;
2323*6185db85Sdougm 			}
2324*6185db85Sdougm 		    }
2325*6185db85Sdougm 		}
2326*6185db85Sdougm 	    } else {
2327*6185db85Sdougm 		/*
2328*6185db85Sdougm 		 * ZFS update. The calling function would have updated
2329*6185db85Sdougm 		 * the internal XML structure. Just need to flag it as
2330*6185db85Sdougm 		 * changed for ZFS.
2331*6185db85Sdougm 		 */
2332*6185db85Sdougm 		zfs_set_update((sa_share_t)group);
2333*6185db85Sdougm 	    }
2334*6185db85Sdougm 	}
2335*6185db85Sdougm 
2336*6185db85Sdougm 	if (name != NULL)
2337*6185db85Sdougm 	    sa_free_attr_string(name);
2338*6185db85Sdougm 	if (valstr != NULL)
2339*6185db85Sdougm 	    sa_free_attr_string(valstr);
2340*6185db85Sdougm 	else if (entry != NULL)
2341*6185db85Sdougm 	    scf_entry_destroy(entry);
2342*6185db85Sdougm 
2343*6185db85Sdougm 	if (ret == -1)
2344*6185db85Sdougm 	    ret = SA_SYSTEM_ERR;
2345*6185db85Sdougm 
2346*6185db85Sdougm 	return (ret);
2347*6185db85Sdougm }
2348*6185db85Sdougm 
2349*6185db85Sdougm /*
2350*6185db85Sdougm  * sa_create_property(name, value)
2351*6185db85Sdougm  *
2352*6185db85Sdougm  * Create a new property with the specified name and value.
2353*6185db85Sdougm  */
2354*6185db85Sdougm 
2355*6185db85Sdougm sa_property_t
2356*6185db85Sdougm sa_create_property(char *name, char *value)
2357*6185db85Sdougm {
2358*6185db85Sdougm 	xmlNodePtr node;
2359*6185db85Sdougm 
2360*6185db85Sdougm 	node = xmlNewNode(NULL, (xmlChar *)"option");
2361*6185db85Sdougm 	if (node != NULL) {
2362*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name);
2363*6185db85Sdougm 		xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value);
2364*6185db85Sdougm 	}
2365*6185db85Sdougm 	return ((sa_property_t)node);
2366*6185db85Sdougm }
2367*6185db85Sdougm 
2368*6185db85Sdougm /*
2369*6185db85Sdougm  * sa_add_property(object, property)
2370*6185db85Sdougm  *
2371*6185db85Sdougm  * Add the specified property to the object. Issue the appropriate
2372*6185db85Sdougm  * transaction or mark a ZFS object as needing an update.
2373*6185db85Sdougm  */
2374*6185db85Sdougm 
2375*6185db85Sdougm int
2376*6185db85Sdougm sa_add_property(void *object, sa_property_t property)
2377*6185db85Sdougm {
2378*6185db85Sdougm 	int ret = SA_OK;
2379*6185db85Sdougm 	sa_group_t parent;
2380*6185db85Sdougm 	sa_group_t group;
2381*6185db85Sdougm 	char *proto;
2382*6185db85Sdougm 
2383*6185db85Sdougm 	proto = sa_get_optionset_attr(object, "type");
2384*6185db85Sdougm 	if (property != NULL) {
2385*6185db85Sdougm 	    if ((ret = sa_valid_property(object, proto, property)) == SA_OK) {
2386*6185db85Sdougm 		property = (sa_property_t)xmlAddChild((xmlNodePtr)object,
2387*6185db85Sdougm 							(xmlNodePtr)property);
2388*6185db85Sdougm 	    } else {
2389*6185db85Sdougm 		if (proto != NULL)
2390*6185db85Sdougm 		    sa_free_attr_string(proto);
2391*6185db85Sdougm 		return (ret);
2392*6185db85Sdougm 	    }
2393*6185db85Sdougm 	}
2394*6185db85Sdougm 
2395*6185db85Sdougm 	if (proto != NULL)
2396*6185db85Sdougm 	    sa_free_attr_string(proto);
2397*6185db85Sdougm 
2398*6185db85Sdougm 	parent = sa_get_parent_group(object);
2399*6185db85Sdougm 	if (!is_persistent(parent)) {
2400*6185db85Sdougm 	    return (ret);
2401*6185db85Sdougm 	}
2402*6185db85Sdougm 
2403*6185db85Sdougm 	if (sa_is_share(parent))
2404*6185db85Sdougm 	    group = sa_get_parent_group(parent);
2405*6185db85Sdougm 	else
2406*6185db85Sdougm 	    group = parent;
2407*6185db85Sdougm 
2408*6185db85Sdougm 	if (property == NULL)
2409*6185db85Sdougm 	    ret = SA_NO_MEMORY;
2410*6185db85Sdougm 	else {
2411*6185db85Sdougm 	    char oname[256];
2412*6185db85Sdougm 
2413*6185db85Sdougm 	    if (!is_zfs_group(group)) {
2414*6185db85Sdougm 		char *id = NULL;
2415*6185db85Sdougm 		if (sa_is_share((sa_group_t)parent)) {
2416*6185db85Sdougm 		    id = sa_get_share_attr((sa_share_t)parent, "id");
2417*6185db85Sdougm 		}
2418*6185db85Sdougm 		if (scf_handle->trans == NULL) {
2419*6185db85Sdougm 		    if (is_nodetype(object, "optionset"))
2420*6185db85Sdougm 			(void) sa_optionset_name((sa_optionset_t)object,
2421*6185db85Sdougm 					    oname, sizeof (oname), id);
2422*6185db85Sdougm 		    else
2423*6185db85Sdougm 			(void) sa_security_name((sa_optionset_t)object,
2424*6185db85Sdougm 					    oname, sizeof (oname), id);
2425*6185db85Sdougm 		    ret = sa_start_transaction(scf_handle, oname);
2426*6185db85Sdougm 		}
2427*6185db85Sdougm 		if (ret == SA_OK) {
2428*6185db85Sdougm 		    char *name;
2429*6185db85Sdougm 		    char *value;
2430*6185db85Sdougm 		    name = sa_get_property_attr(property, "type");
2431*6185db85Sdougm 		    value = sa_get_property_attr(property, "value");
2432*6185db85Sdougm 		    if (name != NULL && value != NULL) {
2433*6185db85Sdougm 			if (scf_handle->scf_state == SCH_STATE_INIT)
2434*6185db85Sdougm 			    ret = sa_set_property(scf_handle, name, value);
2435*6185db85Sdougm 		    } else
2436*6185db85Sdougm 			ret = SA_CONFIG_ERR;
2437*6185db85Sdougm 		    if (name != NULL)
2438*6185db85Sdougm 			sa_free_attr_string(name);
2439*6185db85Sdougm 		    if (value != NULL)
2440*6185db85Sdougm 			sa_free_attr_string(value);
2441*6185db85Sdougm 		}
2442*6185db85Sdougm 		if (id != NULL)
2443*6185db85Sdougm 		    sa_free_attr_string(id);
2444*6185db85Sdougm 	    } else {
2445*6185db85Sdougm 		/*
2446*6185db85Sdougm 		 * ZFS is a special case. We do want to allow editing
2447*6185db85Sdougm 		 * property/security lists since we can have a better
2448*6185db85Sdougm 		 * syntax and we also want to keep things consistent
2449*6185db85Sdougm 		 * when possible.
2450*6185db85Sdougm 		 *
2451*6185db85Sdougm 		 * Right now, we defer until the sa_commit_properties
2452*6185db85Sdougm 		 * so we can get them all at once. We do need to mark
2453*6185db85Sdougm 		 * the share as "changed"
2454*6185db85Sdougm 		 */
2455*6185db85Sdougm 		zfs_set_update((sa_share_t)parent);
2456*6185db85Sdougm 	    }
2457*6185db85Sdougm 	}
2458*6185db85Sdougm 	return (ret);
2459*6185db85Sdougm }
2460*6185db85Sdougm 
2461*6185db85Sdougm /*
2462*6185db85Sdougm  * sa_remove_property(property)
2463*6185db85Sdougm  *
2464*6185db85Sdougm  * Remove the specied property from its containing object. Update the
2465*6185db85Sdougm  * repository as appropriate.
2466*6185db85Sdougm  */
2467*6185db85Sdougm 
2468*6185db85Sdougm int
2469*6185db85Sdougm sa_remove_property(sa_property_t property)
2470*6185db85Sdougm {
2471*6185db85Sdougm 	int ret = SA_OK;
2472*6185db85Sdougm 
2473*6185db85Sdougm 	if (property != NULL) {
2474*6185db85Sdougm 		sa_optionset_t optionset;
2475*6185db85Sdougm 		sa_group_t group;
2476*6185db85Sdougm 		optionset = sa_get_property_parent(property);
2477*6185db85Sdougm 		if (optionset != NULL) {
2478*6185db85Sdougm 		    group = sa_get_optionset_parent(optionset);
2479*6185db85Sdougm 		    if (group != NULL) {
2480*6185db85Sdougm 			ret = sa_set_prop_by_prop(optionset, group, property,
2481*6185db85Sdougm 					    SA_PROP_OP_REMOVE);
2482*6185db85Sdougm 		    }
2483*6185db85Sdougm 		}
2484*6185db85Sdougm 		xmlUnlinkNode((xmlNodePtr)property);
2485*6185db85Sdougm 		xmlFreeNode((xmlNodePtr)property);
2486*6185db85Sdougm 	} else {
2487*6185db85Sdougm 	    ret = SA_NO_SUCH_PROP;
2488*6185db85Sdougm 	}
2489*6185db85Sdougm 	return (ret);
2490*6185db85Sdougm }
2491*6185db85Sdougm 
2492*6185db85Sdougm /*
2493*6185db85Sdougm  * sa_update_property(property, value)
2494*6185db85Sdougm  *
2495*6185db85Sdougm  * Update the specified property to the new value.  If value is NULL,
2496*6185db85Sdougm  * we currently treat this as a remove.
2497*6185db85Sdougm  */
2498*6185db85Sdougm 
2499*6185db85Sdougm int
2500*6185db85Sdougm sa_update_property(sa_property_t property, char *value)
2501*6185db85Sdougm {
2502*6185db85Sdougm 	int ret = SA_OK;
2503*6185db85Sdougm 	if (value == NULL) {
2504*6185db85Sdougm 		return (sa_remove_property(property));
2505*6185db85Sdougm 	} else {
2506*6185db85Sdougm 		sa_optionset_t optionset;
2507*6185db85Sdougm 		sa_group_t group;
2508*6185db85Sdougm 		set_node_attr((void *)property, "value", value);
2509*6185db85Sdougm 		optionset = sa_get_property_parent(property);
2510*6185db85Sdougm 		if (optionset != NULL) {
2511*6185db85Sdougm 		    group = sa_get_optionset_parent(optionset);
2512*6185db85Sdougm 		    if (group != NULL) {
2513*6185db85Sdougm 			ret = sa_set_prop_by_prop(optionset, group, property,
2514*6185db85Sdougm 					    SA_PROP_OP_UPDATE);
2515*6185db85Sdougm 		    }
2516*6185db85Sdougm 		} else {
2517*6185db85Sdougm 		    ret = SA_NO_SUCH_PROP;
2518*6185db85Sdougm 		}
2519*6185db85Sdougm 	}
2520*6185db85Sdougm 	return (ret);
2521*6185db85Sdougm }
2522*6185db85Sdougm 
2523*6185db85Sdougm /*
2524*6185db85Sdougm  *  _sa_get_next_error(node)
2525*6185db85Sdougm  *
2526*6185db85Sdougm  * Get the next (first if node==NULL) error node in the
2527*6185db85Sdougm  * document. "error" nodes are added if there were syntax errors
2528*6185db85Sdougm  * during parsing of the /etc/dfs/dfstab file. They are preserved in
2529*6185db85Sdougm  * comments and recreated in the doc on the next parse.
2530*6185db85Sdougm  */
2531*6185db85Sdougm 
2532*6185db85Sdougm xmlNodePtr
2533*6185db85Sdougm _sa_get_next_error(xmlNodePtr node)
2534*6185db85Sdougm {
2535*6185db85Sdougm 	if (node == NULL) {
2536*6185db85Sdougm 	    for (node = sa_config_tree->xmlChildrenNode;
2537*6185db85Sdougm 		node != NULL; node = node->next)
2538*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"error") == 0)
2539*6185db85Sdougm 		    return (node);
2540*6185db85Sdougm 	} else {
2541*6185db85Sdougm 	    for (node = node->next; node != NULL; node = node->next)
2542*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"error") == 0)
2543*6185db85Sdougm 		    return (node);
2544*6185db85Sdougm 	}
2545*6185db85Sdougm 	return (node);
2546*6185db85Sdougm }
2547*6185db85Sdougm 
2548*6185db85Sdougm /*
2549*6185db85Sdougm  * sa_get_protocol_property(propset, prop)
2550*6185db85Sdougm  *
2551*6185db85Sdougm  * Get the specified protocol specific property. These are global to
2552*6185db85Sdougm  * the protocol and not specific to a group or share.
2553*6185db85Sdougm  */
2554*6185db85Sdougm 
2555*6185db85Sdougm sa_property_t
2556*6185db85Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop)
2557*6185db85Sdougm {
2558*6185db85Sdougm 	xmlNodePtr node = (xmlNodePtr)propset;
2559*6185db85Sdougm 	xmlChar *value = NULL;
2560*6185db85Sdougm 
2561*6185db85Sdougm 	for (node = node->children; node != NULL;
2562*6185db85Sdougm 		node = node->next) {
2563*6185db85Sdougm 	    if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
2564*6185db85Sdougm 		if (prop == NULL)
2565*6185db85Sdougm 		    break;
2566*6185db85Sdougm 		value = xmlGetProp(node, (xmlChar *)"type");
2567*6185db85Sdougm 		if (value != NULL &&
2568*6185db85Sdougm 		    xmlStrcasecmp(value, (xmlChar *)prop) == 0) {
2569*6185db85Sdougm 		    break;
2570*6185db85Sdougm 		}
2571*6185db85Sdougm 		if (value != NULL) {
2572*6185db85Sdougm 		    xmlFree(value);
2573*6185db85Sdougm 		    value = NULL;
2574*6185db85Sdougm 		}
2575*6185db85Sdougm 	    }
2576*6185db85Sdougm 	}
2577*6185db85Sdougm 	if (value != NULL)
2578*6185db85Sdougm 		xmlFree(value);
2579*6185db85Sdougm 	if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) {
2580*6185db85Sdougm 	    /* avoid a non option node -- it is possible to be a text node */
2581*6185db85Sdougm 	    node = NULL;
2582*6185db85Sdougm 	}
2583*6185db85Sdougm 	return ((sa_property_t)node);
2584*6185db85Sdougm }
2585*6185db85Sdougm 
2586*6185db85Sdougm /*
2587*6185db85Sdougm  * sa_get_next_protocol_property(prop)
2588*6185db85Sdougm  *
2589*6185db85Sdougm  * Get the next protocol specific property in the list.
2590*6185db85Sdougm  */
2591*6185db85Sdougm 
2592*6185db85Sdougm sa_property_t
2593*6185db85Sdougm sa_get_next_protocol_property(sa_property_t prop)
2594*6185db85Sdougm {
2595*6185db85Sdougm 	xmlNodePtr node;
2596*6185db85Sdougm 
2597*6185db85Sdougm 	for (node = ((xmlNodePtr)prop)->next; node != NULL;
2598*6185db85Sdougm 		node = node->next) {
2599*6185db85Sdougm 		if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
2600*6185db85Sdougm 			break;
2601*6185db85Sdougm 		}
2602*6185db85Sdougm 	}
2603*6185db85Sdougm 	return ((sa_property_t)node);
2604*6185db85Sdougm }
2605*6185db85Sdougm 
2606*6185db85Sdougm /*
2607*6185db85Sdougm  * sa_set_protocol_property(prop, value)
2608*6185db85Sdougm  *
2609*6185db85Sdougm  * Set the specified property to have the new value.  The protocol
2610*6185db85Sdougm  * specific plugin will then be called to update the property.
2611*6185db85Sdougm  */
2612*6185db85Sdougm 
2613*6185db85Sdougm int
2614*6185db85Sdougm sa_set_protocol_property(sa_property_t prop, char *value)
2615*6185db85Sdougm {
2616*6185db85Sdougm 	sa_protocol_properties_t propset;
2617*6185db85Sdougm 	char *proto;
2618*6185db85Sdougm 	int ret = SA_INVALID_PROTOCOL;
2619*6185db85Sdougm 
2620*6185db85Sdougm 	propset = ((xmlNodePtr)prop)->parent;
2621*6185db85Sdougm 	if (propset != NULL) {
2622*6185db85Sdougm 	    proto = sa_get_optionset_attr(propset, "type");
2623*6185db85Sdougm 	    if (proto != NULL) {
2624*6185db85Sdougm 		set_node_attr((xmlNodePtr)prop, "value", value);
2625*6185db85Sdougm 		ret = sa_proto_set_property(proto, prop);
2626*6185db85Sdougm 		sa_free_attr_string(prop);
2627*6185db85Sdougm 	    }
2628*6185db85Sdougm 	}
2629*6185db85Sdougm 	return (ret);
2630*6185db85Sdougm }
2631*6185db85Sdougm 
2632*6185db85Sdougm /*
2633*6185db85Sdougm  * sa_add_protocol_property(propset, prop)
2634*6185db85Sdougm  *
2635*6185db85Sdougm  * Add a new property to the protocol sepcific property set.
2636*6185db85Sdougm  */
2637*6185db85Sdougm 
2638*6185db85Sdougm int
2639*6185db85Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop)
2640*6185db85Sdougm {
2641*6185db85Sdougm 	xmlNodePtr node;
2642*6185db85Sdougm 
2643*6185db85Sdougm 	/* should check for legitimacy */
2644*6185db85Sdougm 	node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop);
2645*6185db85Sdougm 	if (node != NULL)
2646*6185db85Sdougm 	    return (SA_OK);
2647*6185db85Sdougm 	return (SA_NO_MEMORY);
2648*6185db85Sdougm }
2649*6185db85Sdougm 
2650*6185db85Sdougm /*
2651*6185db85Sdougm  * sa_create_protocol_properties(proto)
2652*6185db85Sdougm  *
2653*6185db85Sdougm  * Create a protocol specifity property set.
2654*6185db85Sdougm  */
2655*6185db85Sdougm 
2656*6185db85Sdougm sa_protocol_properties_t
2657*6185db85Sdougm sa_create_protocol_properties(char *proto)
2658*6185db85Sdougm {
2659*6185db85Sdougm 	xmlNodePtr node;
2660*6185db85Sdougm 	node = xmlNewNode(NULL, (xmlChar *)"propertyset");
2661*6185db85Sdougm 	if (node != NULL) {
2662*6185db85Sdougm 	    xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2663*6185db85Sdougm 	}
2664*6185db85Sdougm 	return (node);
2665*6185db85Sdougm }
2666