13034Sdougm /*
23034Sdougm * CDDL HEADER START
33034Sdougm *
43034Sdougm * The contents of this file are subject to the terms of the
53034Sdougm * Common Development and Distribution License (the "License").
63034Sdougm * You may not use this file except in compliance with the License.
73034Sdougm *
83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm * or http://www.opensolaris.org/os/licensing.
103034Sdougm * See the License for the specific language governing permissions
113034Sdougm * and limitations under the License.
123034Sdougm *
133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm *
193034Sdougm * CDDL HEADER END
203034Sdougm */
213034Sdougm
223034Sdougm /*
23*11337SWilliam.Krier@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
243034Sdougm * Use is subject to license terms.
253034Sdougm */
263034Sdougm
273034Sdougm /* helper functions for using libscf with sharemgr */
283034Sdougm
293034Sdougm #include <libscf.h>
303034Sdougm #include <libxml/parser.h>
313034Sdougm #include <libxml/tree.h>
323034Sdougm #include "libshare.h"
333034Sdougm #include "libshare_impl.h"
343034Sdougm #include "scfutil.h"
353034Sdougm #include <string.h>
365331Samw #include <ctype.h>
373034Sdougm #include <errno.h>
383034Sdougm #include <uuid/uuid.h>
393034Sdougm #include <sys/param.h>
403348Sdougm #include <signal.h>
415951Sdougm #include <sys/time.h>
425997Sdougm #include <libintl.h>
433034Sdougm
443034Sdougm ssize_t scf_max_name_len;
453034Sdougm extern struct sa_proto_plugin *sap_proto_list;
463910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
475951Sdougm static void set_transaction_tstamp(sa_handle_impl_t);
483034Sdougm /*
493034Sdougm * The SMF facility uses some properties that must exist. We want to
503034Sdougm * skip over these when processing protocol options.
513034Sdougm */
523034Sdougm static char *skip_props[] = {
533034Sdougm "modify_authorization",
543034Sdougm "action_authorization",
553034Sdougm "value_authorization",
563034Sdougm NULL
573034Sdougm };
583034Sdougm
593034Sdougm /*
603034Sdougm * sa_scf_fini(handle)
613034Sdougm *
624653Sdougm * Must be called when done. Called with the handle allocated in
633034Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources
643034Sdougm * still in use. Called by sa_fini().
653034Sdougm */
663034Sdougm
673034Sdougm void
sa_scf_fini(scfutilhandle_t * handle)683034Sdougm sa_scf_fini(scfutilhandle_t *handle)
693034Sdougm {
703034Sdougm if (handle != NULL) {
714653Sdougm int unbind = 0;
724653Sdougm if (handle->scope != NULL) {
734653Sdougm unbind = 1;
744653Sdougm scf_scope_destroy(handle->scope);
754653Sdougm }
764653Sdougm if (handle->instance != NULL)
774653Sdougm scf_instance_destroy(handle->instance);
784653Sdougm if (handle->service != NULL)
794653Sdougm scf_service_destroy(handle->service);
804653Sdougm if (handle->pg != NULL)
814653Sdougm scf_pg_destroy(handle->pg);
824653Sdougm if (handle->handle != NULL) {
834653Sdougm handle->scf_state = SCH_STATE_UNINIT;
844653Sdougm if (unbind)
854653Sdougm (void) scf_handle_unbind(handle->handle);
864653Sdougm scf_handle_destroy(handle->handle);
874653Sdougm }
884653Sdougm free(handle);
893034Sdougm }
903034Sdougm }
913034Sdougm
923034Sdougm /*
933034Sdougm * sa_scf_init()
943034Sdougm *
954653Sdougm * Must be called before using any of the SCF functions. Called by
963034Sdougm * sa_init() during the API setup.
973034Sdougm */
983034Sdougm
993034Sdougm scfutilhandle_t *
sa_scf_init(sa_handle_impl_t ihandle)1003910Sdougm sa_scf_init(sa_handle_impl_t ihandle)
1013034Sdougm {
1023034Sdougm scfutilhandle_t *handle;
1033034Sdougm
1043034Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1053034Sdougm if (scf_max_name_len <= 0)
1064653Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1;
1073034Sdougm
1083034Sdougm handle = calloc(1, sizeof (scfutilhandle_t));
1094653Sdougm if (handle == NULL)
1104653Sdougm return (handle);
1114345Sdougm
1124653Sdougm ihandle->scfhandle = handle;
1134653Sdougm handle->scf_state = SCH_STATE_INITIALIZING;
1144653Sdougm handle->handle = scf_handle_create(SCF_VERSION);
1154653Sdougm if (handle->handle == NULL) {
1163034Sdougm free(handle);
1173034Sdougm handle = NULL;
1183034Sdougm (void) printf("libshare could not access SMF repository: %s\n",
1194653Sdougm scf_strerror(scf_error()));
1204653Sdougm return (handle);
1213034Sdougm }
1224653Sdougm if (scf_handle_bind(handle->handle) != 0)
1234653Sdougm goto err;
1244653Sdougm
1254653Sdougm handle->scope = scf_scope_create(handle->handle);
1264653Sdougm handle->service = scf_service_create(handle->handle);
1274653Sdougm handle->pg = scf_pg_create(handle->handle);
1284653Sdougm
1294653Sdougm /* Make sure we have sufficient SMF running */
1304653Sdougm handle->instance = scf_instance_create(handle->handle);
1314653Sdougm if (handle->scope == NULL || handle->service == NULL ||
1324653Sdougm handle->pg == NULL || handle->instance == NULL)
1334653Sdougm goto err;
1344653Sdougm if (scf_handle_get_scope(handle->handle,
1354653Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0)
1364653Sdougm goto err;
1374653Sdougm if (scf_scope_get_service(handle->scope,
1384653Sdougm SA_GROUP_SVC_NAME, handle->service) != 0)
1394653Sdougm goto err;
1404653Sdougm
1414653Sdougm handle->scf_state = SCH_STATE_INIT;
1424653Sdougm if (sa_get_instance(handle, "default") != SA_OK) {
1434653Sdougm sa_group_t defgrp;
1444653Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
1455997Sdougm /* Only NFS enabled for "default" group. */
1465997Sdougm if (defgrp != NULL)
1475997Sdougm (void) sa_create_optionset(defgrp, "nfs");
1484653Sdougm }
1494653Sdougm
1503034Sdougm return (handle);
1513034Sdougm
1524653Sdougm /* Error handling/unwinding */
1533034Sdougm err:
1543034Sdougm (void) sa_scf_fini(handle);
1553034Sdougm (void) printf("libshare SMF initialization problem: %s\n",
1564653Sdougm scf_strerror(scf_error()));
1573034Sdougm return (NULL);
1583034Sdougm }
1593034Sdougm
1603034Sdougm /*
1613034Sdougm * get_scf_limit(name)
1623034Sdougm *
1633034Sdougm * Since we use scf_limit a lot and do the same check and return the
1643034Sdougm * same value if it fails, implement as a function for code
1653034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN
1663034Sdougm * (1024) so we have a reasonable default buffer size.
1673034Sdougm */
1683034Sdougm static ssize_t
get_scf_limit(uint32_t name)1693034Sdougm get_scf_limit(uint32_t name)
1703034Sdougm {
1713034Sdougm ssize_t vallen;
1723034Sdougm
1733034Sdougm vallen = scf_limit(name);
1743034Sdougm if (vallen == (ssize_t)-1)
1754653Sdougm vallen = MAXPATHLEN;
1763034Sdougm return (vallen);
1773034Sdougm }
1783034Sdougm
1793034Sdougm /*
1803034Sdougm * skip_property(name)
1813034Sdougm *
1824653Sdougm * Internal function to check to see if a property is an SMF magic
1833034Sdougm * property that needs to be skipped.
1843034Sdougm */
1853034Sdougm static int
skip_property(char * name)1863034Sdougm skip_property(char *name)
1873034Sdougm {
1883034Sdougm int i;
1893034Sdougm
1903034Sdougm for (i = 0; skip_props[i] != NULL; i++)
1914653Sdougm if (strcmp(name, skip_props[i]) == 0)
1923034Sdougm return (1);
1933034Sdougm return (0);
1943034Sdougm }
1953034Sdougm
1963034Sdougm /*
1973034Sdougm * generate_unique_sharename(sharename)
1983034Sdougm *
1993034Sdougm * Shares are represented in SMF as property groups. Due to share
2003034Sdougm * paths containing characters that are not allowed in SMF names and
2013034Sdougm * the need to be unique, we use UUIDs to construct a unique name.
2023034Sdougm */
2033034Sdougm
2043034Sdougm static void
generate_unique_sharename(char * sharename)2053034Sdougm generate_unique_sharename(char *sharename)
2063034Sdougm {
2073034Sdougm uuid_t uuid;
2083034Sdougm
2093034Sdougm uuid_generate(uuid);
2103034Sdougm (void) strcpy(sharename, "S-");
2113034Sdougm uuid_unparse(uuid, sharename + 2);
2123034Sdougm }
2133034Sdougm
2143034Sdougm /*
2153034Sdougm * valid_protocol(proto)
2163034Sdougm *
2174653Sdougm * Check to see if the specified protocol is a valid one for the
2183034Sdougm * general sharemgr facility. We determine this by checking which
2193034Sdougm * plugin protocols were found.
2203034Sdougm */
2213034Sdougm
2223034Sdougm static int
valid_protocol(char * proto)2233034Sdougm valid_protocol(char *proto)
2243034Sdougm {
2253034Sdougm struct sa_proto_plugin *plugin;
2263034Sdougm for (plugin = sap_proto_list; plugin != NULL;
2273034Sdougm plugin = plugin->plugin_next)
2284653Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
2294653Sdougm return (1);
2303034Sdougm return (0);
2313034Sdougm }
2323034Sdougm
2333034Sdougm /*
2343034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
2353034Sdougm *
2364653Sdougm * Extract the name property group and create the specified type of
2373034Sdougm * node on the provided group. type will be optionset or security.
2383034Sdougm */
2393034Sdougm
2403034Sdougm static int
sa_extract_pgroup(xmlNodePtr root,scfutilhandle_t * handle,scf_propertygroup_t * pg,char * nodetype,char * proto,char * sectype)2413034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
2423034Sdougm scf_propertygroup_t *pg,
2433034Sdougm char *nodetype, char *proto, char *sectype)
2443034Sdougm {
2453034Sdougm xmlNodePtr node;
2463034Sdougm scf_iter_t *iter;
2473034Sdougm scf_property_t *prop;
2483034Sdougm scf_value_t *value;
2493034Sdougm char *name;
2503034Sdougm char *valuestr;
2513034Sdougm ssize_t vallen;
2523034Sdougm int ret = SA_OK;
2533034Sdougm
2543034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2553034Sdougm
2563034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
2574653Sdougm if (node == NULL)
2584653Sdougm return (ret);
2594653Sdougm
2604653Sdougm if (proto != NULL)
2616012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
2624653Sdougm if (sectype != NULL)
2636012Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype",
2646012Sthurlow (xmlChar *)sectype);
2654653Sdougm /*
2664653Sdougm * Have node to work with so iterate over the properties
2674653Sdougm * in the pg and create option sub nodes.
2684653Sdougm */
2694653Sdougm iter = scf_iter_create(handle->handle);
2704653Sdougm value = scf_value_create(handle->handle);
2714653Sdougm prop = scf_property_create(handle->handle);
2724653Sdougm name = malloc(scf_max_name_len);
2734653Sdougm valuestr = malloc(vallen);
2744653Sdougm /*
2754653Sdougm * Want to iterate through the properties and add them
2764653Sdougm * to the base optionset.
2774653Sdougm */
2784653Sdougm if (iter == NULL || value == NULL || prop == NULL ||
2794653Sdougm valuestr == NULL || name == NULL) {
2804653Sdougm ret = SA_NO_MEMORY;
2814653Sdougm goto out;
2824653Sdougm }
2834653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) {
2844653Sdougm /* Now iterate the properties in the group */
2854653Sdougm while (scf_iter_next_property(iter, prop) > 0) {
2864653Sdougm /* have a property */
2874653Sdougm if (scf_property_get_name(prop, name,
2884653Sdougm scf_max_name_len) > 0) {
2894653Sdougm sa_property_t saprop;
2904653Sdougm /* Some properties are part of the framework */
2913034Sdougm if (skip_property(name))
2924653Sdougm continue;
2934653Sdougm if (scf_property_get_value(prop, value) != 0)
2944653Sdougm continue;
2954653Sdougm if (scf_value_get_astring(value, valuestr,
2964653Sdougm vallen) < 0)
2974653Sdougm continue;
2984653Sdougm saprop = sa_create_property(name, valuestr);
2994653Sdougm if (saprop != NULL) {
3003034Sdougm /*
3014653Sdougm * Since in SMF, don't
3023034Sdougm * recurse. Use xmlAddChild
3033034Sdougm * directly, instead.
3043034Sdougm */
3056012Sthurlow (void) xmlAddChild(node,
3064653Sdougm (xmlNodePtr) saprop);
3073034Sdougm }
3083034Sdougm }
3093034Sdougm }
3103034Sdougm }
3114653Sdougm out:
3124653Sdougm /* cleanup to avoid memory leaks */
3134653Sdougm if (value != NULL)
3144653Sdougm scf_value_destroy(value);
3154653Sdougm if (iter != NULL)
3164653Sdougm scf_iter_destroy(iter);
3174653Sdougm if (prop != NULL)
3184653Sdougm scf_property_destroy(prop);
3194653Sdougm if (name != NULL)
3204653Sdougm free(name);
3214653Sdougm if (valuestr != NULL)
3224653Sdougm free(valuestr);
3234653Sdougm
3243034Sdougm return (ret);
3253034Sdougm }
3263034Sdougm
3273034Sdougm /*
3283034Sdougm * sa_extract_attrs(root, handle, instance)
3293034Sdougm *
3304653Sdougm * Local function to extract the actual attributes/properties from the
3313034Sdougm * property group of the service instance. These are the well known
3323034Sdougm * attributes of "state" and "zfs". If additional attributes are
3333034Sdougm * added, they should be added here.
3343034Sdougm */
3353034Sdougm
3363034Sdougm static void
sa_extract_attrs(xmlNodePtr root,scfutilhandle_t * handle,scf_instance_t * instance)3373034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
3383034Sdougm scf_instance_t *instance)
3393034Sdougm {
3403034Sdougm scf_property_t *prop;
3413034Sdougm scf_value_t *value;
3423034Sdougm char *valuestr;
3433034Sdougm ssize_t vallen;
3443034Sdougm
3453034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3463034Sdougm prop = scf_property_create(handle->handle);
3473034Sdougm value = scf_value_create(handle->handle);
3483034Sdougm valuestr = malloc(vallen);
3494653Sdougm if (prop == NULL || value == NULL || valuestr == NULL ||
3504653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
3514653Sdougm goto out;
3524653Sdougm }
3534653Sdougm /*
3544653Sdougm * Have a property group with desired name so now get
3554653Sdougm * the known attributes.
3564653Sdougm */
3574653Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
3584653Sdougm /* Found the property so get the value */
3593034Sdougm if (scf_property_get_value(prop, value) == 0) {
3604653Sdougm if (scf_value_get_astring(value, valuestr,
3614653Sdougm vallen) >= 0) {
3626012Sthurlow (void) xmlSetProp(root, (xmlChar *)"state",
3633034Sdougm (xmlChar *)valuestr);
3644653Sdougm }
3653034Sdougm }
3664653Sdougm }
3674653Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
3684653Sdougm /* Found the property so get the value */
3693034Sdougm if (scf_property_get_value(prop, value) == 0) {
3704653Sdougm if (scf_value_get_astring(value, valuestr,
3714653Sdougm vallen) > 0) {
3726012Sthurlow (void) xmlSetProp(root, (xmlChar *)"zfs",
3733034Sdougm (xmlChar *)valuestr);
3744653Sdougm }
3753034Sdougm }
3763034Sdougm }
3774653Sdougm out:
3783034Sdougm if (valuestr != NULL)
3794653Sdougm free(valuestr);
3803034Sdougm if (value != NULL)
3814653Sdougm scf_value_destroy(value);
3823034Sdougm if (prop != NULL)
3834653Sdougm scf_property_destroy(prop);
3843034Sdougm }
3853034Sdougm
3863034Sdougm /*
3874653Sdougm * List of known share attributes.
3883034Sdougm */
3893034Sdougm
3903034Sdougm static char *share_attr[] = {
3913034Sdougm "path",
3923034Sdougm "id",
3935331Samw "drive-letter",
3945331Samw "exclude",
3953034Sdougm NULL,
3963034Sdougm };
3973034Sdougm
3983034Sdougm static int
is_share_attr(char * name)3993034Sdougm is_share_attr(char *name)
4003034Sdougm {
4013034Sdougm int i;
4023034Sdougm for (i = 0; share_attr[i] != NULL; i++)
4034653Sdougm if (strcmp(name, share_attr[i]) == 0)
4044653Sdougm return (1);
4053034Sdougm return (0);
4063034Sdougm }
4073034Sdougm
4083034Sdougm /*
4095331Samw * _sa_make_resource(node, valuestr)
4105331Samw *
4115331Samw * Make a resource node on the share node. The valusestr will either
4125331Samw * be old format (SMF acceptable string) or new format (pretty much an
4135331Samw * arbitrary string with "nnn:" prefixing in order to persist
4145331Samw * mapping). The input valuestr will get modified in place. This is
4155331Samw * only used in SMF repository parsing. A possible third field will be
4165331Samw * a "description" string.
4175331Samw */
4185331Samw
4195331Samw static void
_sa_make_resource(xmlNodePtr node,char * valuestr)4205331Samw _sa_make_resource(xmlNodePtr node, char *valuestr)
4215331Samw {
4225331Samw char *idx;
4235331Samw char *name;
4245331Samw char *description = NULL;
4255331Samw
4265331Samw idx = valuestr;
4275331Samw name = strchr(valuestr, ':');
4285331Samw if (name == NULL) {
4295331Samw /* this is old form so give an index of "0" */
4305331Samw idx = "0";
4315331Samw name = valuestr;
4325331Samw } else {
4335331Samw /* NUL the ':' and move past it */
4345331Samw *name++ = '\0';
4355331Samw /* There could also be a description string */
4365331Samw description = strchr(name, ':');
4375331Samw if (description != NULL)
4385331Samw *description++ = '\0';
4395331Samw }
4405331Samw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
4415331Samw if (node != NULL) {
4426012Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
4436012Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
4445331Samw /* SMF values are always persistent */
4456012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type",
4466012Sthurlow (xmlChar *)"persist");
4475331Samw if (description != NULL && strlen(description) > 0) {
4485331Samw (void) xmlNewChild(node, NULL, (xmlChar *)"description",
4495331Samw (xmlChar *)description);
4505331Samw }
4515331Samw }
4525331Samw }
4535331Samw
4545331Samw
4555331Samw /*
4563034Sdougm * sa_share_from_pgroup
4573034Sdougm *
4584653Sdougm * Extract the share definition from the share property group. We do
4593034Sdougm * some sanity checking to avoid bad data.
4603034Sdougm *
4613034Sdougm * Since this is only constructing the internal data structures, we
4623034Sdougm * don't use the sa_* functions most of the time.
4633034Sdougm */
4643034Sdougm void
sa_share_from_pgroup(xmlNodePtr root,scfutilhandle_t * handle,scf_propertygroup_t * pg,char * id)4653034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
4663034Sdougm scf_propertygroup_t *pg, char *id)
4673034Sdougm {
4683034Sdougm xmlNodePtr node;
4693034Sdougm char *name;
4703034Sdougm scf_iter_t *iter;
4713034Sdougm scf_property_t *prop;
4723034Sdougm scf_value_t *value;
4733034Sdougm ssize_t vallen;
4743034Sdougm char *valuestr;
4753034Sdougm int ret = SA_OK;
4763348Sdougm int have_path = 0;
4773034Sdougm
4783034Sdougm /*
4793034Sdougm * While preliminary check (starts with 'S') passed before
4803034Sdougm * getting here. Need to make sure it is in ID syntax
4813034Sdougm * (Snnnnnn). Note that shares with properties have similar
4823034Sdougm * pgroups.
4833034Sdougm */
4843034Sdougm vallen = strlen(id);
4853034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
4864653Sdougm uuid_t uuid;
4874653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX,
4884653Sdougm SA_SHARE_PG_PREFIXLEN) != 0 ||
4894653Sdougm uuid_parse(id + 2, uuid) < 0)
4904653Sdougm return;
4914653Sdougm } else {
4923034Sdougm return;
4933034Sdougm }
4943034Sdougm
4953034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
4963034Sdougm
4973034Sdougm iter = scf_iter_create(handle->handle);
4983034Sdougm value = scf_value_create(handle->handle);
4993034Sdougm prop = scf_property_create(handle->handle);
5003034Sdougm name = malloc(scf_max_name_len);
5013034Sdougm valuestr = malloc(vallen);
5023034Sdougm
5033034Sdougm /*
5044653Sdougm * Construct the share XML node. It is similar to sa_add_share
5053034Sdougm * but never changes the repository. Also, there won't be any
5063034Sdougm * ZFS or transient shares. Root will be the group it is
5073034Sdougm * associated with.
5083034Sdougm */
5093034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
5103034Sdougm if (node != NULL) {
5113034Sdougm /*
5124653Sdougm * Make sure the UUID part of the property group is
5133034Sdougm * stored in the share "id" property. We use this
5143034Sdougm * later.
5153034Sdougm */
5166012Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
5176012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type",
5186012Sthurlow (xmlChar *)"persist");
5193034Sdougm }
5203034Sdougm
5214653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL)
5224653Sdougm goto out;
5234653Sdougm
5244653Sdougm /* Iterate over the share pg properties */
5254653Sdougm if (scf_iter_pg_properties(iter, pg) != 0)
5264653Sdougm goto out;
5274653Sdougm
5284653Sdougm while (scf_iter_next_property(iter, prop) > 0) {
5294653Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */
5304653Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
5313034Sdougm if (scf_property_get_value(prop, value) == 0) {
5324653Sdougm if (scf_value_get_astring(value, valuestr,
5334653Sdougm vallen) >= 0) {
5344653Sdougm ret = SA_OK;
5354653Sdougm }
5365331Samw } else if (strcmp(name, "resource") == 0) {
5375331Samw ret = SA_OK;
5383034Sdougm }
5394653Sdougm }
5405331Samw if (ret != SA_OK)
5415331Samw continue;
5425331Samw /*
5435331Samw * Check that we have the "path" property in
5445331Samw * name. The string in name will always be nul
5455331Samw * terminated if scf_property_get_name()
5465331Samw * succeeded.
5475331Samw */
5485331Samw if (strcmp(name, "path") == 0)
5495331Samw have_path = 1;
5505331Samw if (is_share_attr(name)) {
5513348Sdougm /*
5525331Samw * If a share attr, then simple -
5535331Samw * usually path and id name
5543348Sdougm */
5556012Sthurlow (void) xmlSetProp(node, (xmlChar *)name,
5565331Samw (xmlChar *)valuestr);
5575331Samw } else if (strcmp(name, "resource") == 0) {
5585331Samw /*
5595331Samw * Resource names handled differently since
5605331Samw * there can be multiple on each share. The
5615331Samw * "resource" id must be preserved since this
5625331Samw * will be used by some protocols in mapping
5635331Samw * "property spaces" to names and is always
5645331Samw * used to create SMF property groups specific
5655331Samw * to resources. CIFS needs this. The first
5665331Samw * value is present so add and then loop for
5675331Samw * any additional. Since this is new and
5685331Samw * previous values may exist, handle
5695331Samw * conversions.
5705331Samw */
5715331Samw scf_iter_t *viter;
5725331Samw viter = scf_iter_create(handle->handle);
5735331Samw if (viter != NULL &&
5745331Samw scf_iter_property_values(viter, prop) == 0) {
5755331Samw while (scf_iter_next_value(viter, value) > 0) {
5765331Samw /* Have a value so process it */
5775331Samw if (scf_value_get_ustring(value,
5785331Samw valuestr, vallen) >= 0) {
5795331Samw /* have a ustring */
5805331Samw _sa_make_resource(node,
5815331Samw valuestr);
5825331Samw } else if (scf_value_get_astring(value,
5835331Samw valuestr, vallen) >= 0) {
5845331Samw /* have an astring */
5855331Samw _sa_make_resource(node,
5865331Samw valuestr);
5875331Samw }
5884653Sdougm }
5895331Samw scf_iter_destroy(viter);
5905331Samw }
5915331Samw } else {
5925331Samw if (strcmp(name, "description") == 0) {
5935331Samw /* We have a description node */
5945331Samw xmlNodePtr desc;
5955331Samw desc = xmlNewChild(node, NULL,
5965331Samw (xmlChar *)"description", NULL);
5975331Samw if (desc != NULL)
5985331Samw xmlNodeSetContent(desc,
5995331Samw (xmlChar *)valuestr);
6003034Sdougm }
6013034Sdougm }
6023034Sdougm }
6034653Sdougm out:
6043348Sdougm /*
6054653Sdougm * A share without a path is broken so we want to not include
6063348Sdougm * these. They shouldn't happen but if you kill a sharemgr in
6073348Sdougm * the process of creating a share, it could happen. They
6083348Sdougm * should be harmless. It is also possible that another
6093348Sdougm * sharemgr is running and in the process of creating a share.
6103348Sdougm */
6113348Sdougm if (have_path == 0 && node != NULL) {
6124653Sdougm xmlUnlinkNode(node);
6134653Sdougm xmlFreeNode(node);
6143348Sdougm }
6153034Sdougm if (name != NULL)
6164653Sdougm free(name);
6173034Sdougm if (valuestr != NULL)
6184653Sdougm free(valuestr);
6193034Sdougm if (value != NULL)
6204653Sdougm scf_value_destroy(value);
6213034Sdougm if (iter != NULL)
6224653Sdougm scf_iter_destroy(iter);
6233034Sdougm if (prop != NULL)
6244653Sdougm scf_property_destroy(prop);
6253034Sdougm }
6263034Sdougm
6273034Sdougm /*
6283034Sdougm * find_share_by_id(shareid)
6293034Sdougm *
6303034Sdougm * Search all shares in all groups until we find the share represented
6313034Sdougm * by "id".
6323034Sdougm */
6333034Sdougm
6343034Sdougm static sa_share_t
find_share_by_id(sa_handle_t handle,char * shareid)6353910Sdougm find_share_by_id(sa_handle_t handle, char *shareid)
6363034Sdougm {
6373034Sdougm sa_group_t group;
6383034Sdougm sa_share_t share = NULL;
6393034Sdougm char *id = NULL;
6403034Sdougm int done = 0;
6413034Sdougm
6424653Sdougm for (group = sa_get_group(handle, NULL);
6434653Sdougm group != NULL && !done;
6444653Sdougm group = sa_get_next_group(group)) {
6454653Sdougm for (share = sa_get_share(group, NULL);
6464653Sdougm share != NULL;
6474653Sdougm share = sa_get_next_share(share)) {
6483034Sdougm id = sa_get_share_attr(share, "id");
6493034Sdougm if (id != NULL && strcmp(id, shareid) == 0) {
6503034Sdougm sa_free_attr_string(id);
6513034Sdougm id = NULL;
6523034Sdougm done++;
6533034Sdougm break;
6543034Sdougm }
6553034Sdougm if (id != NULL) {
6564653Sdougm sa_free_attr_string(id);
6574653Sdougm id = NULL;
6583034Sdougm }
6593034Sdougm }
6603034Sdougm }
6613034Sdougm return (share);
6623034Sdougm }
6633034Sdougm
6643034Sdougm /*
6655331Samw * find_resource_by_index(share, index)
6665331Samw *
6675331Samw * Search the resource records on the share for the id index.
6685331Samw */
6695331Samw static sa_resource_t
find_resource_by_index(sa_share_t share,char * index)6705331Samw find_resource_by_index(sa_share_t share, char *index)
6715331Samw {
6725331Samw sa_resource_t resource;
6735331Samw sa_resource_t found = NULL;
6745331Samw char *id;
6755331Samw
6765331Samw for (resource = sa_get_share_resource(share, NULL);
6775331Samw resource != NULL && found == NULL;
6785331Samw resource = sa_get_next_resource(resource)) {
6795331Samw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
6805331Samw if (id != NULL) {
6815331Samw if (strcmp(id, index) == 0) {
6825331Samw /* found it so save in "found" */
6835331Samw found = resource;
6845331Samw }
6855331Samw sa_free_attr_string(id);
6865331Samw }
6875331Samw }
6885331Samw return (found);
6895331Samw }
6905331Samw
6915331Samw /*
6925331Samw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
6933034Sdougm *
6944653Sdougm * Extract share properties from the SMF property group. More sanity
6953034Sdougm * checks are done and the share object is created. We ignore some
6963034Sdougm * errors that could exist in the repository and only worry about
6973034Sdougm * property groups that validate in naming.
6983034Sdougm */
6993034Sdougm
7003034Sdougm static int
sa_share_props_from_pgroup(xmlNodePtr root,scfutilhandle_t * handle,scf_propertygroup_t * pg,char * id,sa_handle_t sahandle)7013034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
7023910Sdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
7033034Sdougm {
7043034Sdougm xmlNodePtr node;
7054653Sdougm char *name = NULL;
7064653Sdougm scf_iter_t *iter = NULL;
7074653Sdougm scf_property_t *prop = NULL;
7084653Sdougm scf_value_t *value = NULL;
7093034Sdougm ssize_t vallen;
7104653Sdougm char *valuestr = NULL;
7113034Sdougm int ret = SA_OK;
7123034Sdougm char *sectype = NULL;
7133034Sdougm char *proto;
7143034Sdougm sa_share_t share;
7154653Sdougm uuid_t uuid;
7163034Sdougm
7173034Sdougm /*
7183034Sdougm * While preliminary check (starts with 'S') passed before
7193034Sdougm * getting here. Need to make sure it is in ID syntax
7203034Sdougm * (Snnnnnn). Note that shares with properties have similar
7213034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN
7223034Sdougm * characters, it is likely one of the protocol/security
7233034Sdougm * versions.
7243034Sdougm */
7253034Sdougm vallen = strlen(id);
7264653Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
7274653Sdougm /*
7284653Sdougm * It is ok to not have what we thought since someone might
7294653Sdougm * have added a name via SMF.
7304653Sdougm */
7314653Sdougm return (ret);
7324653Sdougm }
7334653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
7343034Sdougm proto = strchr(id, '_');
7353034Sdougm if (proto == NULL)
7364653Sdougm return (ret);
7373034Sdougm *proto++ = '\0';
7383034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
7394653Sdougm return (ret);
7403034Sdougm /*
7413034Sdougm * probably a legal optionset so check a few more
7423034Sdougm * syntax points below.
7433034Sdougm */
7443034Sdougm if (*proto == '\0') {
7454653Sdougm /* not a valid proto (null) */
7464653Sdougm return (ret);
7473034Sdougm }
7485331Samw
7493034Sdougm sectype = strchr(proto, '_');
7503034Sdougm if (sectype != NULL)
7514653Sdougm *sectype++ = '\0';
7523034Sdougm if (!valid_protocol(proto))
7534653Sdougm return (ret);
7543034Sdougm }
7553034Sdougm
7563034Sdougm /*
7574653Sdougm * To get here, we have a valid protocol and possibly a
7583034Sdougm * security. We now have to find the share that it is really
7593034Sdougm * associated with. The "id" portion of the pgroup name will
7603034Sdougm * match.
7613034Sdougm */
7623034Sdougm
7633910Sdougm share = find_share_by_id(sahandle, id);
7643034Sdougm if (share == NULL)
7654653Sdougm return (SA_BAD_PATH);
7663034Sdougm
7673034Sdougm root = (xmlNodePtr)share;
7683034Sdougm
7693034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
7703034Sdougm
7714653Sdougm if (sectype == NULL)
7724653Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
7734653Sdougm else {
7745331Samw if (isdigit((int)*sectype)) {
7755331Samw sa_resource_t resource;
7765331Samw /*
7775331Samw * If sectype[0] is a digit, then it is an index into
7785331Samw * the resource names. We need to find a resource
7795331Samw * record and then get the properties into an
7805331Samw * optionset. The optionset becomes the "node" and the
7815331Samw * rest is hung off of the share.
7825331Samw */
7835331Samw resource = find_resource_by_index(share, sectype);
7845331Samw if (resource != NULL) {
7855331Samw node = xmlNewChild(resource, NULL,
7865331Samw (xmlChar *)"optionset", NULL);
7875331Samw } else {
7885521Sas200622 /* This shouldn't happen. */
7895331Samw ret = SA_SYSTEM_ERR;
7905521Sas200622 goto out;
7915331Samw }
7925331Samw } else {
7935331Samw /*
7945331Samw * If not a digit, then it is a security type
7955331Samw * (alternate option space). Security types start with
7965331Samw * an alphabetic.
7975331Samw */
7985331Samw node = xmlNewChild(root, NULL, (xmlChar *)"security",
7995331Samw NULL);
8005331Samw if (node != NULL)
8016012Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype",
8025331Samw (xmlChar *)sectype);
8035331Samw }
8044653Sdougm }
8054653Sdougm if (node == NULL) {
8064653Sdougm ret = SA_NO_MEMORY;
8074653Sdougm goto out;
8084653Sdougm }
8094653Sdougm
8106012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
8114653Sdougm /* now find the properties */
8123034Sdougm iter = scf_iter_create(handle->handle);
8133034Sdougm value = scf_value_create(handle->handle);
8143034Sdougm prop = scf_property_create(handle->handle);
8153034Sdougm name = malloc(scf_max_name_len);
8163034Sdougm valuestr = malloc(vallen);
8173034Sdougm
8184653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL)
8194653Sdougm goto out;
8204653Sdougm
8215331Samw /* iterate over the share pg properties */
8224653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) {
8234653Sdougm while (scf_iter_next_property(iter, prop) > 0) {
8243034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */
8253034Sdougm if (scf_property_get_name(prop, name,
8264653Sdougm scf_max_name_len) > 0) {
8274653Sdougm if (scf_property_get_value(prop, value) == 0) {
8284653Sdougm if (scf_value_get_astring(value,
8294653Sdougm valuestr, vallen) >= 0) {
8304653Sdougm ret = SA_OK;
8314653Sdougm }
8323034Sdougm }
8333034Sdougm } else {
8344653Sdougm ret = SA_SYSTEM_ERR;
8353034Sdougm }
8363034Sdougm if (ret == SA_OK) {
8374653Sdougm sa_property_t prop;
8384653Sdougm prop = sa_create_property(name, valuestr);
8394653Sdougm if (prop != NULL)
8404653Sdougm prop = (sa_property_t)xmlAddChild(node,
8414653Sdougm (xmlNodePtr)prop);
8424653Sdougm else
8434653Sdougm ret = SA_NO_MEMORY;
8443034Sdougm }
8453034Sdougm }
8463034Sdougm } else {
8474653Sdougm ret = SA_SYSTEM_ERR;
8483034Sdougm }
8494653Sdougm out:
8503034Sdougm if (iter != NULL)
8514653Sdougm scf_iter_destroy(iter);
8523034Sdougm if (value != NULL)
8534653Sdougm scf_value_destroy(value);
8543034Sdougm if (prop != NULL)
8554653Sdougm scf_property_destroy(prop);
8563034Sdougm if (name != NULL)
8574653Sdougm free(name);
8583034Sdougm if (valuestr != NULL)
8594653Sdougm free(valuestr);
8603034Sdougm return (ret);
8613034Sdougm }
8623034Sdougm
8633034Sdougm /*
8643034Sdougm * sa_extract_group(root, handle, instance)
8653034Sdougm *
8664653Sdougm * Get the config info for this instance of a group and create the XML
8673034Sdougm * subtree from it.
8683034Sdougm */
8693034Sdougm
8703034Sdougm static int
sa_extract_group(xmlNodePtr root,scfutilhandle_t * handle,scf_instance_t * instance,sa_handle_t sahandle)8713034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
8725951Sdougm scf_instance_t *instance, sa_handle_t sahandle)
8733034Sdougm {
8743034Sdougm char *buff;
8753034Sdougm xmlNodePtr node;
8763034Sdougm scf_iter_t *iter;
8773034Sdougm char *proto;
8783034Sdougm char *sectype;
8795997Sdougm boolean_t have_shares = B_FALSE;
8805997Sdougm boolean_t is_default = B_FALSE;
8815997Sdougm boolean_t is_nfs = B_FALSE;
8823034Sdougm int ret = SA_OK;
8833034Sdougm int err;
8843034Sdougm
8853034Sdougm buff = malloc(scf_max_name_len);
8864653Sdougm if (buff == NULL)
8874653Sdougm return (SA_NO_MEMORY);
8884653Sdougm
8893034Sdougm iter = scf_iter_create(handle->handle);
8904653Sdougm if (iter == NULL) {
8914653Sdougm ret = SA_NO_MEMORY;
8924653Sdougm goto out;
8934653Sdougm }
8944653Sdougm
8954653Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
8963034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
8974653Sdougm if (node == NULL) {
8984653Sdougm ret = SA_NO_MEMORY;
8994653Sdougm goto out;
9004653Sdougm }
9016012Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
9024653Sdougm if (strcmp(buff, "default") == 0)
9035997Sdougm is_default = B_TRUE;
9044653Sdougm
9054653Sdougm sa_extract_attrs(node, handle, instance);
9064653Sdougm /*
9074653Sdougm * Iterate through all the property groups
9084653Sdougm * looking for those with security or
9094653Sdougm * optionset prefixes. The names of the
9104653Sdougm * matching pgroups are parsed to get the
9114653Sdougm * protocol, and for security, the sectype.
9124653Sdougm * Syntax is as follows:
9134653Sdougm * optionset | optionset_<proto>
9144653Sdougm * security_default | security_<proto>_<sectype>
9154653Sdougm * "operation" is handled by
9164653Sdougm * sa_extract_attrs().
9174653Sdougm */
9184653Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) {
9194653Sdougm ret = SA_NO_MEMORY;
9204653Sdougm goto out;
9214653Sdougm }
9224653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) {
9234653Sdougm /* Have a pgroup so sort it out */
9244653Sdougm ret = scf_pg_get_name(handle->pg, buff,
9254653Sdougm scf_max_name_len);
9265997Sdougm if (ret <= 0)
9275997Sdougm continue;
9285997Sdougm is_nfs = B_FALSE;
9295997Sdougm
9305997Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
9315997Sdougm sa_share_from_pgroup(node, handle,
9325997Sdougm handle->pg, buff);
9335997Sdougm have_shares = B_TRUE;
9345997Sdougm } else if (strncmp(buff, "optionset", 9) == 0) {
9355997Sdougm char *nodetype = "optionset";
9365997Sdougm /* Have an optionset */
9375997Sdougm sectype = NULL;
9385997Sdougm proto = strchr(buff, '_');
9395997Sdougm if (proto != NULL) {
9405997Sdougm *proto++ = '\0';
9415997Sdougm sectype = strchr(proto, '_');
9425997Sdougm if (sectype != NULL) {
9435997Sdougm *sectype++ = '\0';
9445997Sdougm nodetype = "security";
9453034Sdougm }
9465997Sdougm is_nfs = strcmp(proto, "nfs") == 0;
9475997Sdougm } else if (strlen(buff) > 9) {
9485997Sdougm /*
9495997Sdougm * This can only occur if
9505997Sdougm * someone has made changes
9515997Sdougm * via an SMF command. Since
9525997Sdougm * this would be an unknown
9535997Sdougm * syntax, we just ignore it.
9545997Sdougm */
9555997Sdougm continue;
9565997Sdougm }
9575997Sdougm /*
9585997Sdougm * If the group is not "default" or is
9595997Sdougm * "default" and is_nfs, then extract the
9605997Sdougm * pgroup. If it is_default and !is_nfs,
9615997Sdougm * then we have an error and should remove
9625997Sdougm * the extraneous protocols. We don't care
9635997Sdougm * about errors on scf_pg_delete since we
9645997Sdougm * might not have permission during an
9655997Sdougm * extract only.
9665997Sdougm */
9675997Sdougm if (!is_default || is_nfs) {
9683034Sdougm ret = sa_extract_pgroup(node, handle,
9694653Sdougm handle->pg, nodetype, proto,
9704653Sdougm sectype);
9715997Sdougm } else {
9725997Sdougm err = scf_pg_delete(handle->pg);
9735997Sdougm if (err == 0)
9745997Sdougm (void) fprintf(stderr,
9755997Sdougm dgettext(TEXT_DOMAIN,
9765997Sdougm "Removed protocol \"%s\" "
9775997Sdougm "from group \"default\"\n"),
9785997Sdougm proto);
9793034Sdougm }
9805997Sdougm } else if (strncmp(buff, "security", 8) == 0) {
9815997Sdougm /*
9825997Sdougm * Have a security (note that
9835997Sdougm * this should change in the
9845997Sdougm * future)
9855997Sdougm */
9865997Sdougm proto = strchr(buff, '_');
9875997Sdougm sectype = NULL;
9885997Sdougm if (proto != NULL) {
9895997Sdougm *proto++ = '\0';
9905997Sdougm sectype = strchr(proto, '_');
9915997Sdougm if (sectype != NULL)
9925997Sdougm *sectype++ = '\0';
9935997Sdougm if (strcmp(proto, "default") == 0)
9945997Sdougm proto = NULL;
9955997Sdougm }
9965997Sdougm ret = sa_extract_pgroup(node, handle,
9975997Sdougm handle->pg, "security", proto, sectype);
9983034Sdougm }
9995997Sdougm /* Ignore everything else */
10004653Sdougm }
10014653Sdougm /*
10024653Sdougm * Make sure we have a valid default group.
10034653Sdougm * On first boot, default won't have any
10044653Sdougm * protocols defined and won't be enabled (but
10055997Sdougm * should be). "default" only has NFS enabled on it.
10064653Sdougm */
10074653Sdougm if (is_default) {
10084653Sdougm char *state = sa_get_group_attr((sa_group_t)node,
10094653Sdougm "state");
10103034Sdougm
10114653Sdougm if (state == NULL) {
10123034Sdougm /* set attribute to enabled */
10133034Sdougm (void) sa_set_group_attr((sa_group_t)node,
10144653Sdougm "state", "enabled");
10155997Sdougm (void) sa_create_optionset((sa_group_t)node,
10165997Sdougm "nfs");
10174653Sdougm } else {
10183034Sdougm sa_free_attr_string(state);
10193034Sdougm }
10204653Sdougm }
10214653Sdougm /* Do a second pass if shares were found */
10224653Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
10234653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) {
10243034Sdougm /*
10254653Sdougm * Have a pgroup so see if it is a
10263034Sdougm * share optionset
10273034Sdougm */
10283034Sdougm err = scf_pg_get_name(handle->pg, buff,
10294653Sdougm scf_max_name_len);
10304653Sdougm if (err <= 0)
10314653Sdougm continue;
10324653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
10333034Sdougm ret = sa_share_props_from_pgroup(node,
10344653Sdougm handle, handle->pg, buff,
10354653Sdougm sahandle);
10363034Sdougm }
10373034Sdougm }
10383034Sdougm }
10393034Sdougm }
10404653Sdougm out:
10413034Sdougm if (iter != NULL)
10424653Sdougm scf_iter_destroy(iter);
10433034Sdougm if (buff != NULL)
10444653Sdougm free(buff);
10453034Sdougm return (ret);
10463034Sdougm }
10473034Sdougm
10483034Sdougm /*
10493034Sdougm * sa_extract_defaults(root, handle, instance)
10503034Sdougm *
10514653Sdougm * Local function to find the default properties that live in the
10525331Samw * default instance's "operation" property group.
10533034Sdougm */
10543034Sdougm
10553034Sdougm static void
sa_extract_defaults(xmlNodePtr root,scfutilhandle_t * handle,scf_instance_t * instance)10563034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
10573034Sdougm scf_instance_t *instance)
10583034Sdougm {
10593034Sdougm xmlNodePtr node;
10603034Sdougm scf_property_t *prop;
10613034Sdougm scf_value_t *value;
10623034Sdougm char *valuestr;
10633034Sdougm ssize_t vallen;
10643034Sdougm
10653034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
10663034Sdougm prop = scf_property_create(handle->handle);
10673034Sdougm value = scf_value_create(handle->handle);
10683034Sdougm valuestr = malloc(vallen);
10694653Sdougm
10704653Sdougm if (prop == NULL || value == NULL || vallen == 0 ||
10714653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0)
10724653Sdougm goto out;
10734653Sdougm
10744653Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
10754653Sdougm goto out;
10764653Sdougm
10774653Sdougm /* Found the property so get the value */
10784653Sdougm if (scf_property_get_value(prop, value) == 0) {
10794653Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) {
10803034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
10814653Sdougm NULL);
10823034Sdougm if (node != NULL) {
10836012Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp",
10844653Sdougm (xmlChar *)valuestr);
10856012Sthurlow (void) xmlSetProp(node, (xmlChar *)"path",
10864653Sdougm (xmlChar *)SA_LEGACY_DFSTAB);
10873034Sdougm }
10883034Sdougm }
10893034Sdougm }
10904653Sdougm out:
10913034Sdougm if (valuestr != NULL)
10924653Sdougm free(valuestr);
10933034Sdougm if (value != NULL)
10944653Sdougm scf_value_destroy(value);
10953034Sdougm if (prop != NULL)
10964653Sdougm scf_property_destroy(prop);
10973034Sdougm }
10983034Sdougm
10993034Sdougm
11003034Sdougm /*
11015331Samw * sa_get_config(handle, root, doc, sahandle)
11023034Sdougm *
11034653Sdougm * Walk the SMF repository for /network/shares/group and find all the
11043034Sdougm * instances. These become group names. Then add the XML structure
11053034Sdougm * below the groups based on property groups and properties.
11063034Sdougm */
11073034Sdougm int
sa_get_config(scfutilhandle_t * handle,xmlNodePtr root,sa_handle_t sahandle)11083973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
11093034Sdougm {
11103034Sdougm int ret = SA_OK;
11113034Sdougm scf_instance_t *instance;
11123034Sdougm scf_iter_t *iter;
11133034Sdougm char buff[BUFSIZ * 2];
11143034Sdougm
11153034Sdougm instance = scf_instance_create(handle->handle);
11163034Sdougm iter = scf_iter_create(handle->handle);
11173973Sdougm if (instance != NULL && iter != NULL) {
11184653Sdougm if ((ret = scf_iter_service_instances(iter,
11194653Sdougm handle->service)) == 0) {
11204653Sdougm while ((ret = scf_iter_next_instance(iter,
11214653Sdougm instance)) > 0) {
11224653Sdougm if (scf_instance_get_name(instance, buff,
11234653Sdougm sizeof (buff)) > 0) {
11244653Sdougm if (strcmp(buff, "default") == 0)
11254653Sdougm sa_extract_defaults(root,
11264653Sdougm handle, instance);
11274653Sdougm ret = sa_extract_group(root, handle,
11284653Sdougm instance, sahandle);
11294653Sdougm }
11304653Sdougm }
11313034Sdougm }
11323034Sdougm }
11333973Sdougm
11344653Sdougm /* Always cleanup these */
11353034Sdougm if (instance != NULL)
11364653Sdougm scf_instance_destroy(instance);
11373034Sdougm if (iter != NULL)
11384653Sdougm scf_iter_destroy(iter);
11393034Sdougm return (ret);
11403034Sdougm }
11413034Sdougm
11423034Sdougm /*
11433034Sdougm * sa_get_instance(handle, instance)
11443034Sdougm *
11454653Sdougm * Get the instance of the group service. This is actually the
11463034Sdougm * specific group name. The instance is needed for all property and
11473034Sdougm * control operations.
11483034Sdougm */
11493034Sdougm
11503034Sdougm int
sa_get_instance(scfutilhandle_t * handle,char * instname)11513034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname)
11523034Sdougm {
11533034Sdougm if (scf_service_get_instance(handle->service, instname,
11544653Sdougm handle->instance) != 0) {
11554653Sdougm return (SA_NO_SUCH_GROUP);
11563034Sdougm }
11573034Sdougm return (SA_OK);
11583034Sdougm }
11593034Sdougm
11603034Sdougm /*
11613034Sdougm * sa_create_instance(handle, instname)
11623034Sdougm *
11633034Sdougm * Create a new SMF service instance. There can only be one with a
11643034Sdougm * given name.
11653034Sdougm */
11663034Sdougm
11673034Sdougm int
sa_create_instance(scfutilhandle_t * handle,char * instname)11683034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname)
11693034Sdougm {
11703034Sdougm int ret = SA_OK;
11713034Sdougm char instance[SA_GROUP_INST_LEN];
11723034Sdougm if (scf_service_add_instance(handle->service, instname,
11734653Sdougm handle->instance) != 0) {
11743034Sdougm /* better error returns need to be added based on real error */
11754653Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
11764653Sdougm ret = SA_NO_PERMISSION;
11774653Sdougm else
11784653Sdougm ret = SA_DUPLICATE_NAME;
11793034Sdougm } else {
11804653Sdougm /* have the service created, so enable it */
11814653Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s",
11824653Sdougm SA_SVC_FMRI_BASE, instname);
11834653Sdougm (void) smf_enable_instance(instance, 0);
11843034Sdougm }
11853034Sdougm return (ret);
11863034Sdougm }
11873034Sdougm
11883034Sdougm /*
11893034Sdougm * sa_delete_instance(handle, instname)
11903034Sdougm *
11913034Sdougm * When a group goes away, we also remove the service instance.
11923034Sdougm */
11933034Sdougm
11943034Sdougm int
sa_delete_instance(scfutilhandle_t * handle,char * instname)11953034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname)
11963034Sdougm {
11973034Sdougm int ret;
11983034Sdougm
11993034Sdougm if (strcmp(instname, "default") == 0) {
12004653Sdougm ret = SA_NO_PERMISSION;
12013034Sdougm } else {
12024653Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
12034653Sdougm if (scf_instance_delete(handle->instance) != 0)
12044653Sdougm /* need better analysis */
12054653Sdougm ret = SA_NO_PERMISSION;
12064653Sdougm }
12073034Sdougm }
12083034Sdougm return (ret);
12093034Sdougm }
12103034Sdougm
12113034Sdougm /*
12123034Sdougm * sa_create_pgroup(handle, pgroup)
12133034Sdougm *
12143034Sdougm * create a new property group
12153034Sdougm */
12163034Sdougm
12173034Sdougm int
sa_create_pgroup(scfutilhandle_t * handle,char * pgroup)12183034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
12193034Sdougm {
12203034Sdougm int ret = SA_OK;
12215951Sdougm int persist = 0;
12225951Sdougm
12233034Sdougm /*
12244653Sdougm * Only create a handle if it doesn't exist. It is ok to exist
12253034Sdougm * since the pg handle will be set as a side effect.
12263034Sdougm */
12274653Sdougm if (handle->pg == NULL)
12284653Sdougm handle->pg = scf_pg_create(handle->handle);
12294653Sdougm
12303034Sdougm /*
12315951Sdougm * Special case for a non-persistent property group. This is
12325951Sdougm * internal use only.
12335951Sdougm */
12345951Sdougm if (*pgroup == '*') {
12355951Sdougm persist = SCF_PG_FLAG_NONPERSISTENT;
12365951Sdougm pgroup++;
12375951Sdougm }
12385951Sdougm
12395951Sdougm /*
12404653Sdougm * If the pgroup exists, we are done. If it doesn't, then we
12413034Sdougm * need to actually add one to the service instance.
12423034Sdougm */
12433034Sdougm if (scf_instance_get_pg(handle->instance,
12444653Sdougm pgroup, handle->pg) != 0) {
12455951Sdougm
12464653Sdougm /* Doesn't exist so create one */
12474653Sdougm if (scf_instance_add_pg(handle->instance, pgroup,
12485951Sdougm SCF_GROUP_APPLICATION, persist, handle->pg) != 0) {
12494653Sdougm switch (scf_error()) {
12504653Sdougm case SCF_ERROR_PERMISSION_DENIED:
12514653Sdougm ret = SA_NO_PERMISSION;
12524653Sdougm break;
12534653Sdougm default:
12544653Sdougm ret = SA_SYSTEM_ERR;
12554653Sdougm break;
12564653Sdougm }
12573034Sdougm }
12583034Sdougm }
12593034Sdougm return (ret);
12603034Sdougm }
12613034Sdougm
12623034Sdougm /*
12633034Sdougm * sa_delete_pgroup(handle, pgroup)
12643034Sdougm *
12654653Sdougm * Remove the property group from the current instance of the service,
12663034Sdougm * but only if it actually exists.
12673034Sdougm */
12683034Sdougm
12693034Sdougm int
sa_delete_pgroup(scfutilhandle_t * handle,char * pgroup)12703034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
12713034Sdougm {
12723034Sdougm int ret = SA_OK;
12733034Sdougm /*
12744653Sdougm * Only delete if it does exist.
12753034Sdougm */
12764653Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
12774653Sdougm /* does exist so delete it */
12784653Sdougm if (scf_pg_delete(handle->pg) != 0)
12794653Sdougm ret = SA_SYSTEM_ERR;
12804653Sdougm } else {
12813034Sdougm ret = SA_SYSTEM_ERR;
12823034Sdougm }
12833034Sdougm if (ret == SA_SYSTEM_ERR &&
12843034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) {
12853034Sdougm ret = SA_NO_PERMISSION;
12863034Sdougm }
12873034Sdougm return (ret);
12883034Sdougm }
12893034Sdougm
12903034Sdougm /*
12913034Sdougm * sa_start_transaction(handle, pgroup)
12923034Sdougm *
12933034Sdougm * Start an SMF transaction so we can deal with properties. it would
12943034Sdougm * be nice to not have to expose this, but we have to in order to
12953034Sdougm * optimize.
12963034Sdougm *
12973034Sdougm * Basic model is to hold the transaction in the handle and allow
12983034Sdougm * property adds/deletes/updates to be added then close the
12993034Sdougm * transaction (or abort). There may eventually be a need to handle
13003034Sdougm * other types of transaction mechanisms but we don't do that now.
13013034Sdougm *
13023034Sdougm * An sa_start_transaction must be followed by either an
13033034Sdougm * sa_end_transaction or sa_abort_transaction before another
13043034Sdougm * sa_start_transaction can be done.
13053034Sdougm */
13063034Sdougm
13073034Sdougm int
sa_start_transaction(scfutilhandle_t * handle,char * propgroup)13083034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
13093034Sdougm {
13103034Sdougm int ret = SA_OK;
13113034Sdougm /*
13124653Sdougm * Lookup the property group and create it if it doesn't already
13133034Sdougm * exist.
13143034Sdougm */
13155951Sdougm if (handle == NULL)
13165951Sdougm return (SA_CONFIG_ERR);
13175951Sdougm
13183034Sdougm if (handle->scf_state == SCH_STATE_INIT) {
13194653Sdougm ret = sa_create_pgroup(handle, propgroup);
13204653Sdougm if (ret == SA_OK) {
13214653Sdougm handle->trans = scf_transaction_create(handle->handle);
13224653Sdougm if (handle->trans != NULL) {
13234653Sdougm if (scf_transaction_start(handle->trans,
13244653Sdougm handle->pg) != 0) {
13254653Sdougm ret = SA_SYSTEM_ERR;
13264653Sdougm }
13274653Sdougm if (ret != SA_OK) {
13284653Sdougm scf_transaction_destroy(handle->trans);
13294653Sdougm handle->trans = NULL;
13304653Sdougm }
13314653Sdougm } else {
13324653Sdougm ret = SA_SYSTEM_ERR;
13334653Sdougm }
13343034Sdougm }
13353034Sdougm }
13363034Sdougm if (ret == SA_SYSTEM_ERR &&
13373034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) {
13383034Sdougm ret = SA_NO_PERMISSION;
13393034Sdougm }
13403034Sdougm return (ret);
13413034Sdougm }
13423034Sdougm
13435951Sdougm
13443034Sdougm /*
13455951Sdougm * sa_end_transaction(scfhandle, sahandle)
13463034Sdougm *
13473034Sdougm * Commit the changes that were added to the transaction in the
13483034Sdougm * handle. Do all necessary cleanup.
13493034Sdougm */
13503034Sdougm
13513034Sdougm int
sa_end_transaction(scfutilhandle_t * handle,sa_handle_impl_t sahandle)13525951Sdougm sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle)
13533034Sdougm {
13543034Sdougm int ret = SA_OK;
13553034Sdougm
13565951Sdougm if (handle == NULL || handle->trans == NULL || sahandle == NULL) {
13574653Sdougm ret = SA_SYSTEM_ERR;
13583034Sdougm } else {
13594653Sdougm if (scf_transaction_commit(handle->trans) < 0)
13604653Sdougm ret = SA_SYSTEM_ERR;
13614653Sdougm scf_transaction_destroy_children(handle->trans);
13624653Sdougm scf_transaction_destroy(handle->trans);
13635951Sdougm if (ret == SA_OK)
13645951Sdougm set_transaction_tstamp(sahandle);
13654653Sdougm handle->trans = NULL;
13663034Sdougm }
13673034Sdougm return (ret);
13683034Sdougm }
13693034Sdougm
13703034Sdougm /*
13713034Sdougm * sa_abort_transaction(handle)
13723034Sdougm *
13733034Sdougm * Abort the changes that were added to the transaction in the
13743034Sdougm * handle. Do all necessary cleanup.
13753034Sdougm */
13763034Sdougm
13773034Sdougm void
sa_abort_transaction(scfutilhandle_t * handle)13783034Sdougm sa_abort_transaction(scfutilhandle_t *handle)
13793034Sdougm {
13803034Sdougm if (handle->trans != NULL) {
13814653Sdougm scf_transaction_reset_all(handle->trans);
13824653Sdougm scf_transaction_destroy_children(handle->trans);
13834653Sdougm scf_transaction_destroy(handle->trans);
13844653Sdougm handle->trans = NULL;
13853034Sdougm }
13863034Sdougm }
13873034Sdougm
13883034Sdougm /*
13895951Sdougm * set_transaction_tstamp(sahandle)
13905951Sdougm *
13915951Sdougm * After a successful transaction commit, update the timestamp of the
13925951Sdougm * last transaction. This lets us detect changes from other processes.
13935951Sdougm */
13945951Sdougm static void
set_transaction_tstamp(sa_handle_impl_t sahandle)13955951Sdougm set_transaction_tstamp(sa_handle_impl_t sahandle)
13965951Sdougm {
13975951Sdougm char tstring[32];
13985951Sdougm struct timeval tv;
13995951Sdougm scfutilhandle_t *scfhandle;
14005951Sdougm
14015951Sdougm if (sahandle == NULL || sahandle->scfhandle == NULL)
14025951Sdougm return;
14035951Sdougm
14045951Sdougm scfhandle = sahandle->scfhandle;
14055951Sdougm
14065951Sdougm if (sa_get_instance(scfhandle, "default") != SA_OK)
14075951Sdougm return;
14085951Sdougm
14095951Sdougm if (gettimeofday(&tv, NULL) != 0)
14105951Sdougm return;
14115951Sdougm
14125951Sdougm if (sa_start_transaction(scfhandle, "*state") != SA_OK)
14135951Sdougm return;
14145951Sdougm
14155951Sdougm sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv));
14165951Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans);
14175951Sdougm if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) ==
14185951Sdougm SA_OK) {
14195951Sdougm /*
14205951Sdougm * While best if it succeeds, a failure doesn't cause
14215951Sdougm * problems and we will ignore it anyway.
14225951Sdougm */
14235951Sdougm (void) scf_transaction_commit(scfhandle->trans);
14245951Sdougm scf_transaction_destroy_children(scfhandle->trans);
14255951Sdougm scf_transaction_destroy(scfhandle->trans);
14265951Sdougm } else {
14275951Sdougm sa_abort_transaction(scfhandle);
14285951Sdougm }
14295951Sdougm }
14305951Sdougm
14315951Sdougm /*
14323034Sdougm * sa_set_property(handle, prop, value)
14333034Sdougm *
14344653Sdougm * Set a property transaction entry into the pending SMF transaction.
14353034Sdougm */
14363034Sdougm
14373034Sdougm int
sa_set_property(scfutilhandle_t * handle,char * propname,char * valstr)14383034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
14393034Sdougm {
14403034Sdougm int ret = SA_OK;
14413034Sdougm scf_value_t *value;
14423034Sdougm scf_transaction_entry_t *entry;
14433034Sdougm /*
14444653Sdougm * Properties must be set in transactions and don't take
14453034Sdougm * effect until the transaction has been ended/committed.
14463034Sdougm */
14473034Sdougm value = scf_value_create(handle->handle);
14483034Sdougm entry = scf_entry_create(handle->handle);
14493034Sdougm if (value != NULL && entry != NULL) {
14504653Sdougm if (scf_transaction_property_change(handle->trans, entry,
14514653Sdougm propname, SCF_TYPE_ASTRING) == 0 ||
14524653Sdougm scf_transaction_property_new(handle->trans, entry,
14534653Sdougm propname, SCF_TYPE_ASTRING) == 0) {
14544653Sdougm if (scf_value_set_astring(value, valstr) == 0) {
14554653Sdougm if (scf_entry_add_value(entry, value) != 0) {
14564653Sdougm ret = SA_SYSTEM_ERR;
14574653Sdougm scf_value_destroy(value);
14584653Sdougm }
14594653Sdougm /* The value is in the transaction */
14604653Sdougm value = NULL;
14614653Sdougm } else {
14624653Sdougm /* Value couldn't be constructed */
14634653Sdougm ret = SA_SYSTEM_ERR;
14644653Sdougm }
14654653Sdougm /* The entry is in the transaction */
14664653Sdougm entry = NULL;
14674653Sdougm } else {
14683034Sdougm ret = SA_SYSTEM_ERR;
14693034Sdougm }
14704653Sdougm } else {
14713034Sdougm ret = SA_SYSTEM_ERR;
14723034Sdougm }
14733034Sdougm if (ret == SA_SYSTEM_ERR) {
14744653Sdougm switch (scf_error()) {
14754653Sdougm case SCF_ERROR_PERMISSION_DENIED:
14764653Sdougm ret = SA_NO_PERMISSION;
14774653Sdougm break;
14784653Sdougm }
14793034Sdougm }
14803034Sdougm /*
14814653Sdougm * Cleanup if there were any errors that didn't leave these
14823034Sdougm * values where they would be cleaned up later.
14833034Sdougm */
14843034Sdougm if (value != NULL)
14854653Sdougm scf_value_destroy(value);
14863034Sdougm if (entry != NULL)
14874653Sdougm scf_entry_destroy(entry);
14883034Sdougm return (ret);
14893034Sdougm }
14903034Sdougm
14913034Sdougm /*
14925331Samw * check_resource(share)
14935331Samw *
14945331Samw * Check to see if share has any persistent resources. We don't want
14955331Samw * to save if they are all transient.
14965331Samw */
14975331Samw static int
check_resource(sa_share_t share)14985331Samw check_resource(sa_share_t share)
14995331Samw {
15005331Samw sa_resource_t resource;
15015331Samw int ret = B_FALSE;
15025331Samw
15035331Samw for (resource = sa_get_share_resource(share, NULL);
15045331Samw resource != NULL && ret == B_FALSE;
15055331Samw resource = sa_get_next_resource(resource)) {
15065331Samw char *type;
15075331Samw type = sa_get_resource_attr(resource, "type");
15085331Samw if (type != NULL) {
15095331Samw if (strcmp(type, "transient") != 0) {
15105331Samw ret = B_TRUE;
15115331Samw }
15125331Samw sa_free_attr_string(type);
15135331Samw }
15145331Samw }
15155331Samw return (ret);
15165331Samw }
15175331Samw
15185331Samw /*
15195331Samw * sa_set_resource_property(handle, prop, value)
15205331Samw *
15215331Samw * set a property transaction entry into the pending SMF
15225331Samw * transaction. We don't want to include any transient resources
15235331Samw */
15245331Samw
15255331Samw static int
sa_set_resource_property(scfutilhandle_t * handle,sa_share_t share)15265331Samw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
15275331Samw {
15285331Samw int ret = SA_OK;
15295331Samw scf_value_t *value;
15305331Samw scf_transaction_entry_t *entry;
15315331Samw sa_resource_t resource;
15325331Samw char *valstr;
15335331Samw char *idstr;
15345331Samw char *description;
15355331Samw char *propstr = NULL;
15365331Samw size_t strsize;
15375331Samw
15385331Samw /* don't bother if no persistent resources */
15395331Samw if (check_resource(share) == B_FALSE)
15405331Samw return (ret);
15415331Samw
15425331Samw /*
15435331Samw * properties must be set in transactions and don't take
15445331Samw * effect until the transaction has been ended/committed.
15455331Samw */
15465331Samw entry = scf_entry_create(handle->handle);
15475331Samw if (entry == NULL)
15485331Samw return (SA_SYSTEM_ERR);
15495331Samw
15505331Samw if (scf_transaction_property_change(handle->trans, entry,
15515331Samw "resource", SCF_TYPE_ASTRING) != 0 &&
15525331Samw scf_transaction_property_new(handle->trans, entry,
15535331Samw "resource", SCF_TYPE_ASTRING) != 0) {
15545331Samw scf_entry_destroy(entry);
15555331Samw return (SA_SYSTEM_ERR);
15565331Samw
15575331Samw }
15585331Samw for (resource = sa_get_share_resource(share, NULL);
15595331Samw resource != NULL;
15605331Samw resource = sa_get_next_resource(resource)) {
15615331Samw value = scf_value_create(handle->handle);
15625331Samw if (value == NULL) {
15635331Samw ret = SA_NO_MEMORY;
15645331Samw break;
15655331Samw }
15665331Samw /* Get size of complete string */
15675331Samw valstr = sa_get_resource_attr(resource, "name");
15685331Samw idstr = sa_get_resource_attr(resource, "id");
15695331Samw description = sa_get_resource_description(resource);
15705331Samw strsize = (valstr != NULL) ? strlen(valstr) : 0;
15715331Samw strsize += (idstr != NULL) ? strlen(idstr) : 0;
15725331Samw strsize += (description != NULL) ? strlen(description) : 0;
15735331Samw if (strsize > 0) {
15745331Samw strsize += 3; /* add nul and ':' */
15755331Samw propstr = (char *)malloc(strsize);
15765331Samw if (propstr == NULL) {
15775331Samw scf_value_destroy(value);
15785331Samw ret = SA_NO_MEMORY;
15795331Samw goto err;
15805331Samw }
15815331Samw if (idstr == NULL)
15825331Samw (void) snprintf(propstr, strsize, "%s",
15835331Samw valstr ? valstr : "");
15845331Samw else
15855331Samw (void) snprintf(propstr, strsize, "%s:%s:%s",
1586*11337SWilliam.Krier@Sun.COM idstr, valstr ? valstr : "",
15875331Samw description ? description : "");
15885331Samw if (scf_value_set_astring(value, propstr) != 0) {
15895331Samw ret = SA_SYSTEM_ERR;
15905331Samw free(propstr);
15915331Samw scf_value_destroy(value);
15925331Samw break;
15935331Samw }
15945331Samw if (scf_entry_add_value(entry, value) != 0) {
15955331Samw ret = SA_SYSTEM_ERR;
15965331Samw free(propstr);
15975331Samw scf_value_destroy(value);
15985331Samw break;
15995331Samw }
16005331Samw /* the value is in the transaction */
16015331Samw value = NULL;
16025331Samw free(propstr);
16035331Samw }
16045331Samw err:
1605*11337SWilliam.Krier@Sun.COM if (valstr != NULL) {
16065331Samw sa_free_attr_string(valstr);
1607*11337SWilliam.Krier@Sun.COM valstr = NULL;
1608*11337SWilliam.Krier@Sun.COM }
1609*11337SWilliam.Krier@Sun.COM if (idstr != NULL) {
16105331Samw sa_free_attr_string(idstr);
1611*11337SWilliam.Krier@Sun.COM idstr = NULL;
1612*11337SWilliam.Krier@Sun.COM }
1613*11337SWilliam.Krier@Sun.COM if (description != NULL) {
16145331Samw sa_free_share_description(description);
1615*11337SWilliam.Krier@Sun.COM description = NULL;
1616*11337SWilliam.Krier@Sun.COM }
16175331Samw }
16185331Samw /* the entry is in the transaction */
16195331Samw entry = NULL;
16205331Samw
1621*11337SWilliam.Krier@Sun.COM if (valstr != NULL)
1622*11337SWilliam.Krier@Sun.COM sa_free_attr_string(valstr);
1623*11337SWilliam.Krier@Sun.COM if (idstr != NULL)
1624*11337SWilliam.Krier@Sun.COM sa_free_attr_string(idstr);
1625*11337SWilliam.Krier@Sun.COM if (description != NULL)
1626*11337SWilliam.Krier@Sun.COM sa_free_share_description(description);
1627*11337SWilliam.Krier@Sun.COM
16285331Samw if (ret == SA_SYSTEM_ERR) {
16295331Samw switch (scf_error()) {
16305331Samw case SCF_ERROR_PERMISSION_DENIED:
16315331Samw ret = SA_NO_PERMISSION;
16325331Samw break;
16335331Samw }
16345331Samw }
16355331Samw /*
16365331Samw * cleanup if there were any errors that didn't leave
16375331Samw * these values where they would be cleaned up later.
16385331Samw */
16395331Samw if (entry != NULL)
16405331Samw scf_entry_destroy(entry);
16415331Samw
16425331Samw return (ret);
16435331Samw }
16445331Samw
16455331Samw /*
16463034Sdougm * sa_commit_share(handle, group, share)
16473034Sdougm *
16484653Sdougm * Commit this share to the repository.
16493034Sdougm * properties are added if they exist but can be added later.
16503034Sdougm * Need to add to dfstab and sharetab, if appropriate.
16513034Sdougm */
16523034Sdougm int
sa_commit_share(scfutilhandle_t * handle,sa_group_t group,sa_share_t share)16533034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
16543034Sdougm {
16553034Sdougm int ret = SA_OK;
16563034Sdougm char *groupname;
16573034Sdougm char *name;
16583034Sdougm char *description;
16593034Sdougm char *sharename;
16603034Sdougm ssize_t proplen;
16613034Sdougm char *propstring;
16623034Sdougm
16633034Sdougm /*
16644653Sdougm * Don't commit in the zfs group. We do commit legacy
16653034Sdougm * (default) and all other groups/shares. ZFS is handled
16663034Sdougm * through the ZFS configuration rather than SMF.
16673034Sdougm */
16683034Sdougm
16693034Sdougm groupname = sa_get_group_attr(group, "name");
16703034Sdougm if (groupname != NULL) {
16714653Sdougm if (strcmp(groupname, "zfs") == 0) {
16724653Sdougm /*
16734653Sdougm * Adding to the ZFS group will result in the sharenfs
16744653Sdougm * property being set but we don't want to do anything
16754653Sdougm * SMF related at this point.
16764653Sdougm */
16774653Sdougm sa_free_attr_string(groupname);
16784653Sdougm return (ret);
16794653Sdougm }
16803034Sdougm }
16813034Sdougm
16823034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
16833034Sdougm propstring = malloc(proplen);
16843034Sdougm if (propstring == NULL)
16854653Sdougm ret = SA_NO_MEMORY;
16863034Sdougm
16873034Sdougm if (groupname != NULL && ret == SA_OK) {
16884653Sdougm ret = sa_get_instance(handle, groupname);
16894653Sdougm sa_free_attr_string(groupname);
16904653Sdougm groupname = NULL;
16914653Sdougm sharename = sa_get_share_attr(share, "id");
16924653Sdougm if (sharename == NULL) {
16934653Sdougm /* slipped by */
16944653Sdougm char shname[SA_SHARE_UUID_BUFLEN];
16954653Sdougm generate_unique_sharename(shname);
16966012Sthurlow (void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
16973034Sdougm (xmlChar *)shname);
16984653Sdougm sharename = strdup(shname);
16993034Sdougm }
17004653Sdougm if (sharename != NULL) {
17014653Sdougm sigset_t old, new;
17024653Sdougm /*
17034653Sdougm * Have a share name allocated so create a pgroup for
17044653Sdougm * it. It may already exist, but that is OK. In order
17054653Sdougm * to avoid creating a share pgroup that doesn't have
17064653Sdougm * a path property, block signals around the critical
17074653Sdougm * region of creating the share pgroup and props.
17084653Sdougm */
17094653Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new);
17104653Sdougm (void) sigaddset(&new, SIGHUP);
17114653Sdougm (void) sigaddset(&new, SIGINT);
17124653Sdougm (void) sigaddset(&new, SIGQUIT);
17134653Sdougm (void) sigaddset(&new, SIGTSTP);
17144653Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old);
17154653Sdougm
17164653Sdougm ret = sa_create_pgroup(handle, sharename);
17174653Sdougm if (ret == SA_OK) {
17184653Sdougm /*
17194653Sdougm * Now start the transaction for the
17204653Sdougm * properties that define this share. They may
17214653Sdougm * exist so attempt to update before create.
17224653Sdougm */
17234653Sdougm ret = sa_start_transaction(handle, sharename);
17244653Sdougm }
17254653Sdougm if (ret == SA_OK) {
17264653Sdougm name = sa_get_share_attr(share, "path");
17274653Sdougm if (name != NULL) {
17284653Sdougm /*
17294653Sdougm * There needs to be a path
17304653Sdougm * for a share to exist.
17314653Sdougm */
17324653Sdougm ret = sa_set_property(handle, "path",
17334653Sdougm name);
17344653Sdougm sa_free_attr_string(name);
17354653Sdougm } else {
17364653Sdougm ret = SA_NO_MEMORY;
17374653Sdougm }
17384653Sdougm }
17394653Sdougm if (ret == SA_OK) {
17405331Samw name = sa_get_share_attr(share, "drive-letter");
17415331Samw if (name != NULL) {
17425331Samw /* A drive letter may exist for SMB */
17434653Sdougm ret = sa_set_property(handle,
17445331Samw "drive-letter", name);
17455331Samw sa_free_attr_string(name);
17464653Sdougm }
17474653Sdougm }
17484653Sdougm if (ret == SA_OK) {
17495331Samw name = sa_get_share_attr(share, "exclude");
17505331Samw if (name != NULL) {
17515331Samw /*
17525331Samw * In special cases need to
17535331Samw * exclude proto enable.
17545331Samw */
17555331Samw ret = sa_set_property(handle,
17565331Samw "exclude", name);
17575331Samw sa_free_attr_string(name);
17585331Samw }
17595331Samw }
17605331Samw if (ret == SA_OK) {
17615331Samw /*
17625331Samw * If there are resource names, bundle them up
17635331Samw * and save appropriately.
17645331Samw */
17655331Samw ret = sa_set_resource_property(handle, share);
17665331Samw }
17675331Samw
17685331Samw if (ret == SA_OK) {
17694653Sdougm description = sa_get_share_description(share);
17704653Sdougm if (description != NULL) {
17714653Sdougm ret = sa_set_property(handle,
17724653Sdougm "description",
17734653Sdougm description);
17744653Sdougm sa_free_share_description(description);
17754653Sdougm }
17764653Sdougm }
17774653Sdougm /* Make sure we cleanup the transaction */
17784653Sdougm if (ret == SA_OK) {
17795951Sdougm sa_handle_impl_t sahandle;
17805951Sdougm sahandle = (sa_handle_impl_t)
17815951Sdougm sa_find_group_handle(group);
17825951Sdougm if (sahandle != NULL)
17835951Sdougm ret = sa_end_transaction(handle,
17845951Sdougm sahandle);
17855951Sdougm else
17865951Sdougm ret = SA_SYSTEM_ERR;
17874653Sdougm } else {
17884653Sdougm sa_abort_transaction(handle);
17894653Sdougm }
17904653Sdougm
17914653Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL);
17924653Sdougm
17934653Sdougm free(sharename);
17943034Sdougm }
17953034Sdougm }
17963034Sdougm if (ret == SA_SYSTEM_ERR) {
17974653Sdougm int err = scf_error();
17984653Sdougm if (err == SCF_ERROR_PERMISSION_DENIED)
17994653Sdougm ret = SA_NO_PERMISSION;
18003034Sdougm }
18013034Sdougm if (propstring != NULL)
18024653Sdougm free(propstring);
18033034Sdougm if (groupname != NULL)
18044653Sdougm sa_free_attr_string(groupname);
18053034Sdougm
18063034Sdougm return (ret);
18073034Sdougm }
18083034Sdougm
18093034Sdougm /*
18105331Samw * remove_resources(handle, share, shareid)
18115331Samw *
18125331Samw * If the share has resources, remove all of them and their
18135331Samw * optionsets.
18145331Samw */
18155331Samw static int
remove_resources(scfutilhandle_t * handle,sa_share_t share,char * shareid)18165331Samw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
18175331Samw {
18185331Samw sa_resource_t resource;
18195331Samw sa_optionset_t opt;
18205331Samw char *proto;
18215331Samw char *id;
18225331Samw ssize_t proplen;
18235331Samw char *propstring;
18245331Samw int ret = SA_OK;
18255331Samw
18265331Samw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
18275331Samw propstring = malloc(proplen);
18285331Samw if (propstring == NULL)
18295331Samw return (SA_NO_MEMORY);
18305331Samw
18315331Samw for (resource = sa_get_share_resource(share, NULL);
18325331Samw resource != NULL; resource = sa_get_next_resource(resource)) {
18335331Samw id = sa_get_resource_attr(resource, "id");
18345331Samw if (id == NULL)
18355331Samw continue;
18365331Samw for (opt = sa_get_optionset(resource, NULL);
18375331Samw opt != NULL; opt = sa_get_next_optionset(resource)) {
18385331Samw proto = sa_get_optionset_attr(opt, "type");
18395331Samw if (proto != NULL) {
18405331Samw (void) snprintf(propstring, proplen,
18415331Samw "%s_%s_%s", shareid, proto, id);
18425331Samw ret = sa_delete_pgroup(handle, propstring);
18435331Samw sa_free_attr_string(proto);
18445331Samw }
18455331Samw }
18465331Samw sa_free_attr_string(id);
18475331Samw }
18485331Samw free(propstring);
18495331Samw return (ret);
18505331Samw }
18515331Samw
18525331Samw /*
18533034Sdougm * sa_delete_share(handle, group, share)
18543034Sdougm *
18554653Sdougm * Remove the specified share from the group (and service instance).
18563034Sdougm */
18573034Sdougm
18583034Sdougm int
sa_delete_share(scfutilhandle_t * handle,sa_group_t group,sa_share_t share)18593034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
18603034Sdougm {
18613034Sdougm int ret = SA_OK;
18623034Sdougm char *groupname = NULL;
18633034Sdougm char *shareid = NULL;
18643034Sdougm sa_optionset_t opt;
18653034Sdougm sa_security_t sec;
18663034Sdougm ssize_t proplen;
18673034Sdougm char *propstring;
18683034Sdougm
18693034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
18703034Sdougm propstring = malloc(proplen);
18713034Sdougm if (propstring == NULL)
18724653Sdougm ret = SA_NO_MEMORY;
18733034Sdougm
18743034Sdougm if (ret == SA_OK) {
18754653Sdougm groupname = sa_get_group_attr(group, "name");
18764653Sdougm shareid = sa_get_share_attr(share, "id");
18774653Sdougm if (groupname == NULL || shareid == NULL) {
18784653Sdougm ret = SA_CONFIG_ERR;
18794653Sdougm goto out;
18804653Sdougm }
18813034Sdougm ret = sa_get_instance(handle, groupname);
18823034Sdougm if (ret == SA_OK) {
18835331Samw /* If a share has resources, remove them */
18845331Samw ret = remove_resources(handle, share, shareid);
18854653Sdougm /* If a share has properties, remove them */
18864653Sdougm ret = sa_delete_pgroup(handle, shareid);
18874653Sdougm for (opt = sa_get_optionset(share, NULL);
18884653Sdougm opt != NULL;
18894653Sdougm opt = sa_get_next_optionset(opt)) {
18904653Sdougm char *proto;
18914653Sdougm proto = sa_get_optionset_attr(opt, "type");
18924653Sdougm if (proto != NULL) {
18934653Sdougm (void) snprintf(propstring,
18944653Sdougm proplen, "%s_%s", shareid,
18954653Sdougm proto);
18964653Sdougm ret = sa_delete_pgroup(handle,
18974653Sdougm propstring);
18984653Sdougm sa_free_attr_string(proto);
18994653Sdougm } else {
19004653Sdougm ret = SA_NO_MEMORY;
19014653Sdougm }
19023034Sdougm }
19033034Sdougm /*
19044653Sdougm * If a share has security/negotiable
19053034Sdougm * properties, remove them.
19063034Sdougm */
19074653Sdougm for (sec = sa_get_security(share, NULL, NULL);
19084653Sdougm sec != NULL;
19094653Sdougm sec = sa_get_next_security(sec)) {
19104653Sdougm char *proto;
19114653Sdougm char *sectype;
19124653Sdougm proto = sa_get_security_attr(sec, "type");
19134653Sdougm sectype = sa_get_security_attr(sec, "sectype");
19144653Sdougm if (proto != NULL && sectype != NULL) {
19154653Sdougm (void) snprintf(propstring, proplen,
19164653Sdougm "%s_%s_%s", shareid, proto,
19174653Sdougm sectype);
19184653Sdougm ret = sa_delete_pgroup(handle,
19194653Sdougm propstring);
19204653Sdougm } else {
19214653Sdougm ret = SA_NO_MEMORY;
19224653Sdougm }
19234653Sdougm if (proto != NULL)
19244653Sdougm sa_free_attr_string(proto);
19254653Sdougm if (sectype != NULL)
19264653Sdougm sa_free_attr_string(sectype);
19273034Sdougm }
19283034Sdougm }
19293034Sdougm }
19304653Sdougm out:
19313034Sdougm if (groupname != NULL)
19324653Sdougm sa_free_attr_string(groupname);
19333034Sdougm if (shareid != NULL)
19344653Sdougm sa_free_attr_string(shareid);
19353034Sdougm if (propstring != NULL)
19364653Sdougm free(propstring);
19373034Sdougm
19383034Sdougm return (ret);
19393034Sdougm }
1940