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*5951Sdougm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* helper functions for using libscf with sharemgr */ 303034Sdougm 313034Sdougm #include <libscf.h> 323034Sdougm #include <libxml/parser.h> 333034Sdougm #include <libxml/tree.h> 343034Sdougm #include "libshare.h" 353034Sdougm #include "libshare_impl.h" 363034Sdougm #include "scfutil.h" 373034Sdougm #include <string.h> 385331Samw #include <ctype.h> 393034Sdougm #include <errno.h> 403034Sdougm #include <uuid/uuid.h> 413034Sdougm #include <sys/param.h> 423348Sdougm #include <signal.h> 43*5951Sdougm #include <sys/time.h> 443034Sdougm 453034Sdougm ssize_t scf_max_name_len; 463034Sdougm extern struct sa_proto_plugin *sap_proto_list; 473910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 48*5951Sdougm static void set_transaction_tstamp(sa_handle_impl_t); 493034Sdougm /* 503034Sdougm * The SMF facility uses some properties that must exist. We want to 513034Sdougm * skip over these when processing protocol options. 523034Sdougm */ 533034Sdougm static char *skip_props[] = { 543034Sdougm "modify_authorization", 553034Sdougm "action_authorization", 563034Sdougm "value_authorization", 573034Sdougm NULL 583034Sdougm }; 593034Sdougm 603034Sdougm /* 613034Sdougm * sa_scf_fini(handle) 623034Sdougm * 634653Sdougm * Must be called when done. Called with the handle allocated in 643034Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 653034Sdougm * still in use. Called by sa_fini(). 663034Sdougm */ 673034Sdougm 683034Sdougm void 693034Sdougm sa_scf_fini(scfutilhandle_t *handle) 703034Sdougm { 713034Sdougm if (handle != NULL) { 724653Sdougm int unbind = 0; 734653Sdougm if (handle->scope != NULL) { 744653Sdougm unbind = 1; 754653Sdougm scf_scope_destroy(handle->scope); 764653Sdougm } 774653Sdougm if (handle->instance != NULL) 784653Sdougm scf_instance_destroy(handle->instance); 794653Sdougm if (handle->service != NULL) 804653Sdougm scf_service_destroy(handle->service); 814653Sdougm if (handle->pg != NULL) 824653Sdougm scf_pg_destroy(handle->pg); 834653Sdougm if (handle->handle != NULL) { 844653Sdougm handle->scf_state = SCH_STATE_UNINIT; 854653Sdougm if (unbind) 864653Sdougm (void) scf_handle_unbind(handle->handle); 874653Sdougm scf_handle_destroy(handle->handle); 884653Sdougm } 894653Sdougm free(handle); 903034Sdougm } 913034Sdougm } 923034Sdougm 933034Sdougm /* 943034Sdougm * sa_scf_init() 953034Sdougm * 964653Sdougm * Must be called before using any of the SCF functions. Called by 973034Sdougm * sa_init() during the API setup. 983034Sdougm */ 993034Sdougm 1003034Sdougm scfutilhandle_t * 1013910Sdougm sa_scf_init(sa_handle_impl_t ihandle) 1023034Sdougm { 1033034Sdougm scfutilhandle_t *handle; 1043034Sdougm 1053034Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1063034Sdougm if (scf_max_name_len <= 0) 1074653Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1083034Sdougm 1093034Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 1104653Sdougm if (handle == NULL) 1114653Sdougm return (handle); 1124345Sdougm 1134653Sdougm ihandle->scfhandle = handle; 1144653Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1154653Sdougm handle->handle = scf_handle_create(SCF_VERSION); 1164653Sdougm if (handle->handle == NULL) { 1173034Sdougm free(handle); 1183034Sdougm handle = NULL; 1193034Sdougm (void) printf("libshare could not access SMF repository: %s\n", 1204653Sdougm scf_strerror(scf_error())); 1214653Sdougm return (handle); 1223034Sdougm } 1234653Sdougm if (scf_handle_bind(handle->handle) != 0) 1244653Sdougm goto err; 1254653Sdougm 1264653Sdougm handle->scope = scf_scope_create(handle->handle); 1274653Sdougm handle->service = scf_service_create(handle->handle); 1284653Sdougm handle->pg = scf_pg_create(handle->handle); 1294653Sdougm 1304653Sdougm /* Make sure we have sufficient SMF running */ 1314653Sdougm handle->instance = scf_instance_create(handle->handle); 1324653Sdougm if (handle->scope == NULL || handle->service == NULL || 1334653Sdougm handle->pg == NULL || handle->instance == NULL) 1344653Sdougm goto err; 1354653Sdougm if (scf_handle_get_scope(handle->handle, 1364653Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0) 1374653Sdougm goto err; 1384653Sdougm if (scf_scope_get_service(handle->scope, 1394653Sdougm SA_GROUP_SVC_NAME, handle->service) != 0) 1404653Sdougm goto err; 1414653Sdougm 1424653Sdougm handle->scf_state = SCH_STATE_INIT; 1434653Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1444653Sdougm char **protolist; 1454653Sdougm int numprotos, i; 1464653Sdougm sa_group_t defgrp; 1474653Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1484653Sdougm if (defgrp != NULL) { 1494653Sdougm numprotos = sa_get_protocols( 1504653Sdougm &protolist); 1514653Sdougm for (i = 0; i < numprotos; i++) 1524653Sdougm (void) sa_create_optionset(defgrp, 1534653Sdougm protolist[i]); 1544653Sdougm if (protolist != NULL) 1554653Sdougm free(protolist); 1564653Sdougm } 1574653Sdougm } 1584653Sdougm 1593034Sdougm return (handle); 1603034Sdougm 1614653Sdougm /* Error handling/unwinding */ 1623034Sdougm err: 1633034Sdougm (void) sa_scf_fini(handle); 1643034Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1654653Sdougm scf_strerror(scf_error())); 1663034Sdougm return (NULL); 1673034Sdougm } 1683034Sdougm 1693034Sdougm /* 1703034Sdougm * get_scf_limit(name) 1713034Sdougm * 1723034Sdougm * Since we use scf_limit a lot and do the same check and return the 1733034Sdougm * same value if it fails, implement as a function for code 1743034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1753034Sdougm * (1024) so we have a reasonable default buffer size. 1763034Sdougm */ 1773034Sdougm static ssize_t 1783034Sdougm get_scf_limit(uint32_t name) 1793034Sdougm { 1803034Sdougm ssize_t vallen; 1813034Sdougm 1823034Sdougm vallen = scf_limit(name); 1833034Sdougm if (vallen == (ssize_t)-1) 1844653Sdougm vallen = MAXPATHLEN; 1853034Sdougm return (vallen); 1863034Sdougm } 1873034Sdougm 1883034Sdougm /* 1893034Sdougm * skip_property(name) 1903034Sdougm * 1914653Sdougm * Internal function to check to see if a property is an SMF magic 1923034Sdougm * property that needs to be skipped. 1933034Sdougm */ 1943034Sdougm static int 1953034Sdougm skip_property(char *name) 1963034Sdougm { 1973034Sdougm int i; 1983034Sdougm 1993034Sdougm for (i = 0; skip_props[i] != NULL; i++) 2004653Sdougm if (strcmp(name, skip_props[i]) == 0) 2013034Sdougm return (1); 2023034Sdougm return (0); 2033034Sdougm } 2043034Sdougm 2053034Sdougm /* 2063034Sdougm * generate_unique_sharename(sharename) 2073034Sdougm * 2083034Sdougm * Shares are represented in SMF as property groups. Due to share 2093034Sdougm * paths containing characters that are not allowed in SMF names and 2103034Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2113034Sdougm */ 2123034Sdougm 2133034Sdougm static void 2143034Sdougm generate_unique_sharename(char *sharename) 2153034Sdougm { 2163034Sdougm uuid_t uuid; 2173034Sdougm 2183034Sdougm uuid_generate(uuid); 2193034Sdougm (void) strcpy(sharename, "S-"); 2203034Sdougm uuid_unparse(uuid, sharename + 2); 2213034Sdougm } 2223034Sdougm 2233034Sdougm /* 2243034Sdougm * valid_protocol(proto) 2253034Sdougm * 2264653Sdougm * Check to see if the specified protocol is a valid one for the 2273034Sdougm * general sharemgr facility. We determine this by checking which 2283034Sdougm * plugin protocols were found. 2293034Sdougm */ 2303034Sdougm 2313034Sdougm static int 2323034Sdougm valid_protocol(char *proto) 2333034Sdougm { 2343034Sdougm struct sa_proto_plugin *plugin; 2353034Sdougm for (plugin = sap_proto_list; plugin != NULL; 2363034Sdougm plugin = plugin->plugin_next) 2374653Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2384653Sdougm return (1); 2393034Sdougm return (0); 2403034Sdougm } 2413034Sdougm 2423034Sdougm /* 2433034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2443034Sdougm * 2454653Sdougm * Extract the name property group and create the specified type of 2463034Sdougm * node on the provided group. type will be optionset or security. 2473034Sdougm */ 2483034Sdougm 2493034Sdougm static int 2503034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2513034Sdougm scf_propertygroup_t *pg, 2523034Sdougm char *nodetype, char *proto, char *sectype) 2533034Sdougm { 2543034Sdougm xmlNodePtr node; 2553034Sdougm scf_iter_t *iter; 2563034Sdougm scf_property_t *prop; 2573034Sdougm scf_value_t *value; 2583034Sdougm char *name; 2593034Sdougm char *valuestr; 2603034Sdougm ssize_t vallen; 2613034Sdougm int ret = SA_OK; 2623034Sdougm 2633034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2643034Sdougm 2653034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 2664653Sdougm if (node == NULL) 2674653Sdougm return (ret); 2684653Sdougm 2694653Sdougm if (proto != NULL) 2703034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2714653Sdougm if (sectype != NULL) 2723034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2734653Sdougm /* 2744653Sdougm * Have node to work with so iterate over the properties 2754653Sdougm * in the pg and create option sub nodes. 2764653Sdougm */ 2774653Sdougm iter = scf_iter_create(handle->handle); 2784653Sdougm value = scf_value_create(handle->handle); 2794653Sdougm prop = scf_property_create(handle->handle); 2804653Sdougm name = malloc(scf_max_name_len); 2814653Sdougm valuestr = malloc(vallen); 2824653Sdougm /* 2834653Sdougm * Want to iterate through the properties and add them 2844653Sdougm * to the base optionset. 2854653Sdougm */ 2864653Sdougm if (iter == NULL || value == NULL || prop == NULL || 2874653Sdougm valuestr == NULL || name == NULL) { 2884653Sdougm ret = SA_NO_MEMORY; 2894653Sdougm goto out; 2904653Sdougm } 2914653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 2924653Sdougm /* Now iterate the properties in the group */ 2934653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2944653Sdougm /* have a property */ 2954653Sdougm if (scf_property_get_name(prop, name, 2964653Sdougm scf_max_name_len) > 0) { 2974653Sdougm sa_property_t saprop; 2984653Sdougm /* Some properties are part of the framework */ 2993034Sdougm if (skip_property(name)) 3004653Sdougm continue; 3014653Sdougm if (scf_property_get_value(prop, value) != 0) 3024653Sdougm continue; 3034653Sdougm if (scf_value_get_astring(value, valuestr, 3044653Sdougm vallen) < 0) 3054653Sdougm continue; 3064653Sdougm saprop = sa_create_property(name, valuestr); 3074653Sdougm if (saprop != NULL) { 3083034Sdougm /* 3094653Sdougm * Since in SMF, don't 3103034Sdougm * recurse. Use xmlAddChild 3113034Sdougm * directly, instead. 3123034Sdougm */ 3134653Sdougm xmlAddChild(node, 3144653Sdougm (xmlNodePtr) saprop); 3153034Sdougm } 3163034Sdougm } 3173034Sdougm } 3183034Sdougm } 3194653Sdougm out: 3204653Sdougm /* cleanup to avoid memory leaks */ 3214653Sdougm if (value != NULL) 3224653Sdougm scf_value_destroy(value); 3234653Sdougm if (iter != NULL) 3244653Sdougm scf_iter_destroy(iter); 3254653Sdougm if (prop != NULL) 3264653Sdougm scf_property_destroy(prop); 3274653Sdougm if (name != NULL) 3284653Sdougm free(name); 3294653Sdougm if (valuestr != NULL) 3304653Sdougm free(valuestr); 3314653Sdougm 3323034Sdougm return (ret); 3333034Sdougm } 3343034Sdougm 3353034Sdougm /* 3363034Sdougm * sa_extract_attrs(root, handle, instance) 3373034Sdougm * 3384653Sdougm * Local function to extract the actual attributes/properties from the 3393034Sdougm * property group of the service instance. These are the well known 3403034Sdougm * attributes of "state" and "zfs". If additional attributes are 3413034Sdougm * added, they should be added here. 3423034Sdougm */ 3433034Sdougm 3443034Sdougm static void 3453034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3463034Sdougm scf_instance_t *instance) 3473034Sdougm { 3483034Sdougm scf_property_t *prop; 3493034Sdougm scf_value_t *value; 3503034Sdougm char *valuestr; 3513034Sdougm ssize_t vallen; 3523034Sdougm 3533034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3543034Sdougm prop = scf_property_create(handle->handle); 3553034Sdougm value = scf_value_create(handle->handle); 3563034Sdougm valuestr = malloc(vallen); 3574653Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 3584653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 3594653Sdougm goto out; 3604653Sdougm } 3614653Sdougm /* 3624653Sdougm * Have a property group with desired name so now get 3634653Sdougm * the known attributes. 3644653Sdougm */ 3654653Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 3664653Sdougm /* Found the property so get the value */ 3673034Sdougm if (scf_property_get_value(prop, value) == 0) { 3684653Sdougm if (scf_value_get_astring(value, valuestr, 3694653Sdougm vallen) >= 0) { 3704653Sdougm xmlSetProp(root, (xmlChar *)"state", 3713034Sdougm (xmlChar *)valuestr); 3724653Sdougm } 3733034Sdougm } 3744653Sdougm } 3754653Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 3764653Sdougm /* Found the property so get the value */ 3773034Sdougm if (scf_property_get_value(prop, value) == 0) { 3784653Sdougm if (scf_value_get_astring(value, valuestr, 3794653Sdougm vallen) > 0) { 3804653Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3813034Sdougm (xmlChar *)valuestr); 3824653Sdougm } 3833034Sdougm } 3843034Sdougm } 3854653Sdougm out: 3863034Sdougm if (valuestr != NULL) 3874653Sdougm free(valuestr); 3883034Sdougm if (value != NULL) 3894653Sdougm scf_value_destroy(value); 3903034Sdougm if (prop != NULL) 3914653Sdougm scf_property_destroy(prop); 3923034Sdougm } 3933034Sdougm 3943034Sdougm /* 3954653Sdougm * List of known share attributes. 3963034Sdougm */ 3973034Sdougm 3983034Sdougm static char *share_attr[] = { 3993034Sdougm "path", 4003034Sdougm "id", 4015331Samw "drive-letter", 4025331Samw "exclude", 4033034Sdougm NULL, 4043034Sdougm }; 4053034Sdougm 4063034Sdougm static int 4073034Sdougm is_share_attr(char *name) 4083034Sdougm { 4093034Sdougm int i; 4103034Sdougm for (i = 0; share_attr[i] != NULL; i++) 4114653Sdougm if (strcmp(name, share_attr[i]) == 0) 4124653Sdougm return (1); 4133034Sdougm return (0); 4143034Sdougm } 4153034Sdougm 4163034Sdougm /* 4175331Samw * _sa_make_resource(node, valuestr) 4185331Samw * 4195331Samw * Make a resource node on the share node. The valusestr will either 4205331Samw * be old format (SMF acceptable string) or new format (pretty much an 4215331Samw * arbitrary string with "nnn:" prefixing in order to persist 4225331Samw * mapping). The input valuestr will get modified in place. This is 4235331Samw * only used in SMF repository parsing. A possible third field will be 4245331Samw * a "description" string. 4255331Samw */ 4265331Samw 4275331Samw static void 4285331Samw _sa_make_resource(xmlNodePtr node, char *valuestr) 4295331Samw { 4305331Samw char *idx; 4315331Samw char *name; 4325331Samw char *description = NULL; 4335331Samw 4345331Samw idx = valuestr; 4355331Samw name = strchr(valuestr, ':'); 4365331Samw if (name == NULL) { 4375331Samw /* this is old form so give an index of "0" */ 4385331Samw idx = "0"; 4395331Samw name = valuestr; 4405331Samw } else { 4415331Samw /* NUL the ':' and move past it */ 4425331Samw *name++ = '\0'; 4435331Samw /* There could also be a description string */ 4445331Samw description = strchr(name, ':'); 4455331Samw if (description != NULL) 4465331Samw *description++ = '\0'; 4475331Samw } 4485331Samw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 4495331Samw if (node != NULL) { 4505331Samw xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 4515331Samw xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 4525331Samw /* SMF values are always persistent */ 4535331Samw xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 4545331Samw if (description != NULL && strlen(description) > 0) { 4555331Samw (void) xmlNewChild(node, NULL, (xmlChar *)"description", 4565331Samw (xmlChar *)description); 4575331Samw } 4585331Samw } 4595331Samw } 4605331Samw 4615331Samw 4625331Samw /* 4633034Sdougm * sa_share_from_pgroup 4643034Sdougm * 4654653Sdougm * Extract the share definition from the share property group. We do 4663034Sdougm * some sanity checking to avoid bad data. 4673034Sdougm * 4683034Sdougm * Since this is only constructing the internal data structures, we 4693034Sdougm * don't use the sa_* functions most of the time. 4703034Sdougm */ 4713034Sdougm void 4723034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4733034Sdougm scf_propertygroup_t *pg, char *id) 4743034Sdougm { 4753034Sdougm xmlNodePtr node; 4763034Sdougm char *name; 4773034Sdougm scf_iter_t *iter; 4783034Sdougm scf_property_t *prop; 4793034Sdougm scf_value_t *value; 4803034Sdougm ssize_t vallen; 4813034Sdougm char *valuestr; 4823034Sdougm int ret = SA_OK; 4833348Sdougm int have_path = 0; 4843034Sdougm 4853034Sdougm /* 4863034Sdougm * While preliminary check (starts with 'S') passed before 4873034Sdougm * getting here. Need to make sure it is in ID syntax 4883034Sdougm * (Snnnnnn). Note that shares with properties have similar 4893034Sdougm * pgroups. 4903034Sdougm */ 4913034Sdougm vallen = strlen(id); 4923034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4934653Sdougm uuid_t uuid; 4944653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 4954653Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4964653Sdougm uuid_parse(id + 2, uuid) < 0) 4974653Sdougm return; 4984653Sdougm } else { 4993034Sdougm return; 5003034Sdougm } 5013034Sdougm 5023034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 5033034Sdougm 5043034Sdougm iter = scf_iter_create(handle->handle); 5053034Sdougm value = scf_value_create(handle->handle); 5063034Sdougm prop = scf_property_create(handle->handle); 5073034Sdougm name = malloc(scf_max_name_len); 5083034Sdougm valuestr = malloc(vallen); 5093034Sdougm 5103034Sdougm /* 5114653Sdougm * Construct the share XML node. It is similar to sa_add_share 5123034Sdougm * but never changes the repository. Also, there won't be any 5133034Sdougm * ZFS or transient shares. Root will be the group it is 5143034Sdougm * associated with. 5153034Sdougm */ 5163034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 5173034Sdougm if (node != NULL) { 5183034Sdougm /* 5194653Sdougm * Make sure the UUID part of the property group is 5203034Sdougm * stored in the share "id" property. We use this 5213034Sdougm * later. 5223034Sdougm */ 5234653Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 5244653Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 5253034Sdougm } 5263034Sdougm 5274653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 5284653Sdougm goto out; 5294653Sdougm 5304653Sdougm /* Iterate over the share pg properties */ 5314653Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 5324653Sdougm goto out; 5334653Sdougm 5344653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 5354653Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 5364653Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 5373034Sdougm if (scf_property_get_value(prop, value) == 0) { 5384653Sdougm if (scf_value_get_astring(value, valuestr, 5394653Sdougm vallen) >= 0) { 5404653Sdougm ret = SA_OK; 5414653Sdougm } 5425331Samw } else if (strcmp(name, "resource") == 0) { 5435331Samw ret = SA_OK; 5443034Sdougm } 5454653Sdougm } 5465331Samw if (ret != SA_OK) 5475331Samw continue; 5485331Samw /* 5495331Samw * Check that we have the "path" property in 5505331Samw * name. The string in name will always be nul 5515331Samw * terminated if scf_property_get_name() 5525331Samw * succeeded. 5535331Samw */ 5545331Samw if (strcmp(name, "path") == 0) 5555331Samw have_path = 1; 5565331Samw if (is_share_attr(name)) { 5573348Sdougm /* 5585331Samw * If a share attr, then simple - 5595331Samw * usually path and id name 5603348Sdougm */ 5615331Samw xmlSetProp(node, (xmlChar *)name, 5625331Samw (xmlChar *)valuestr); 5635331Samw } else if (strcmp(name, "resource") == 0) { 5645331Samw /* 5655331Samw * Resource names handled differently since 5665331Samw * there can be multiple on each share. The 5675331Samw * "resource" id must be preserved since this 5685331Samw * will be used by some protocols in mapping 5695331Samw * "property spaces" to names and is always 5705331Samw * used to create SMF property groups specific 5715331Samw * to resources. CIFS needs this. The first 5725331Samw * value is present so add and then loop for 5735331Samw * any additional. Since this is new and 5745331Samw * previous values may exist, handle 5755331Samw * conversions. 5765331Samw */ 5775331Samw scf_iter_t *viter; 5785331Samw viter = scf_iter_create(handle->handle); 5795331Samw if (viter != NULL && 5805331Samw scf_iter_property_values(viter, prop) == 0) { 5815331Samw while (scf_iter_next_value(viter, value) > 0) { 5825331Samw /* Have a value so process it */ 5835331Samw if (scf_value_get_ustring(value, 5845331Samw valuestr, vallen) >= 0) { 5855331Samw /* have a ustring */ 5865331Samw _sa_make_resource(node, 5875331Samw valuestr); 5885331Samw } else if (scf_value_get_astring(value, 5895331Samw valuestr, vallen) >= 0) { 5905331Samw /* have an astring */ 5915331Samw _sa_make_resource(node, 5925331Samw valuestr); 5935331Samw } 5944653Sdougm } 5955331Samw scf_iter_destroy(viter); 5965331Samw } 5975331Samw } else { 5985331Samw if (strcmp(name, "description") == 0) { 5995331Samw /* We have a description node */ 6005331Samw xmlNodePtr desc; 6015331Samw desc = xmlNewChild(node, NULL, 6025331Samw (xmlChar *)"description", NULL); 6035331Samw if (desc != NULL) 6045331Samw xmlNodeSetContent(desc, 6055331Samw (xmlChar *)valuestr); 6063034Sdougm } 6073034Sdougm } 6083034Sdougm } 6094653Sdougm out: 6103348Sdougm /* 6114653Sdougm * A share without a path is broken so we want to not include 6123348Sdougm * these. They shouldn't happen but if you kill a sharemgr in 6133348Sdougm * the process of creating a share, it could happen. They 6143348Sdougm * should be harmless. It is also possible that another 6153348Sdougm * sharemgr is running and in the process of creating a share. 6163348Sdougm */ 6173348Sdougm if (have_path == 0 && node != NULL) { 6184653Sdougm xmlUnlinkNode(node); 6194653Sdougm xmlFreeNode(node); 6203348Sdougm } 6213034Sdougm if (name != NULL) 6224653Sdougm free(name); 6233034Sdougm if (valuestr != NULL) 6244653Sdougm free(valuestr); 6253034Sdougm if (value != NULL) 6264653Sdougm scf_value_destroy(value); 6273034Sdougm if (iter != NULL) 6284653Sdougm scf_iter_destroy(iter); 6293034Sdougm if (prop != NULL) 6304653Sdougm scf_property_destroy(prop); 6313034Sdougm } 6323034Sdougm 6333034Sdougm /* 6343034Sdougm * find_share_by_id(shareid) 6353034Sdougm * 6363034Sdougm * Search all shares in all groups until we find the share represented 6373034Sdougm * by "id". 6383034Sdougm */ 6393034Sdougm 6403034Sdougm static sa_share_t 6413910Sdougm find_share_by_id(sa_handle_t handle, char *shareid) 6423034Sdougm { 6433034Sdougm sa_group_t group; 6443034Sdougm sa_share_t share = NULL; 6453034Sdougm char *id = NULL; 6463034Sdougm int done = 0; 6473034Sdougm 6484653Sdougm for (group = sa_get_group(handle, NULL); 6494653Sdougm group != NULL && !done; 6504653Sdougm group = sa_get_next_group(group)) { 6514653Sdougm for (share = sa_get_share(group, NULL); 6524653Sdougm share != NULL; 6534653Sdougm share = sa_get_next_share(share)) { 6543034Sdougm id = sa_get_share_attr(share, "id"); 6553034Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 6563034Sdougm sa_free_attr_string(id); 6573034Sdougm id = NULL; 6583034Sdougm done++; 6593034Sdougm break; 6603034Sdougm } 6613034Sdougm if (id != NULL) { 6624653Sdougm sa_free_attr_string(id); 6634653Sdougm id = NULL; 6643034Sdougm } 6653034Sdougm } 6663034Sdougm } 6673034Sdougm return (share); 6683034Sdougm } 6693034Sdougm 6703034Sdougm /* 6715331Samw * find_resource_by_index(share, index) 6725331Samw * 6735331Samw * Search the resource records on the share for the id index. 6745331Samw */ 6755331Samw static sa_resource_t 6765331Samw find_resource_by_index(sa_share_t share, char *index) 6775331Samw { 6785331Samw sa_resource_t resource; 6795331Samw sa_resource_t found = NULL; 6805331Samw char *id; 6815331Samw 6825331Samw for (resource = sa_get_share_resource(share, NULL); 6835331Samw resource != NULL && found == NULL; 6845331Samw resource = sa_get_next_resource(resource)) { 6855331Samw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 6865331Samw if (id != NULL) { 6875331Samw if (strcmp(id, index) == 0) { 6885331Samw /* found it so save in "found" */ 6895331Samw found = resource; 6905331Samw } 6915331Samw sa_free_attr_string(id); 6925331Samw } 6935331Samw } 6945331Samw return (found); 6955331Samw } 6965331Samw 6975331Samw /* 6985331Samw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 6993034Sdougm * 7004653Sdougm * Extract share properties from the SMF property group. More sanity 7013034Sdougm * checks are done and the share object is created. We ignore some 7023034Sdougm * errors that could exist in the repository and only worry about 7033034Sdougm * property groups that validate in naming. 7043034Sdougm */ 7053034Sdougm 7063034Sdougm static int 7073034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 7083910Sdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 7093034Sdougm { 7103034Sdougm xmlNodePtr node; 7114653Sdougm char *name = NULL; 7124653Sdougm scf_iter_t *iter = NULL; 7134653Sdougm scf_property_t *prop = NULL; 7144653Sdougm scf_value_t *value = NULL; 7153034Sdougm ssize_t vallen; 7164653Sdougm char *valuestr = NULL; 7173034Sdougm int ret = SA_OK; 7183034Sdougm char *sectype = NULL; 7193034Sdougm char *proto; 7203034Sdougm sa_share_t share; 7214653Sdougm uuid_t uuid; 7223034Sdougm 7233034Sdougm /* 7243034Sdougm * While preliminary check (starts with 'S') passed before 7253034Sdougm * getting here. Need to make sure it is in ID syntax 7263034Sdougm * (Snnnnnn). Note that shares with properties have similar 7273034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 7283034Sdougm * characters, it is likely one of the protocol/security 7293034Sdougm * versions. 7303034Sdougm */ 7313034Sdougm vallen = strlen(id); 7324653Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 7334653Sdougm /* 7344653Sdougm * It is ok to not have what we thought since someone might 7354653Sdougm * have added a name via SMF. 7364653Sdougm */ 7374653Sdougm return (ret); 7384653Sdougm } 7394653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 7403034Sdougm proto = strchr(id, '_'); 7413034Sdougm if (proto == NULL) 7424653Sdougm return (ret); 7433034Sdougm *proto++ = '\0'; 7443034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 7454653Sdougm return (ret); 7463034Sdougm /* 7473034Sdougm * probably a legal optionset so check a few more 7483034Sdougm * syntax points below. 7493034Sdougm */ 7503034Sdougm if (*proto == '\0') { 7514653Sdougm /* not a valid proto (null) */ 7524653Sdougm return (ret); 7533034Sdougm } 7545331Samw 7553034Sdougm sectype = strchr(proto, '_'); 7563034Sdougm if (sectype != NULL) 7574653Sdougm *sectype++ = '\0'; 7583034Sdougm if (!valid_protocol(proto)) 7594653Sdougm return (ret); 7603034Sdougm } 7613034Sdougm 7623034Sdougm /* 7634653Sdougm * To get here, we have a valid protocol and possibly a 7643034Sdougm * security. We now have to find the share that it is really 7653034Sdougm * associated with. The "id" portion of the pgroup name will 7663034Sdougm * match. 7673034Sdougm */ 7683034Sdougm 7693910Sdougm share = find_share_by_id(sahandle, id); 7703034Sdougm if (share == NULL) 7714653Sdougm return (SA_BAD_PATH); 7723034Sdougm 7733034Sdougm root = (xmlNodePtr)share; 7743034Sdougm 7753034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 7763034Sdougm 7774653Sdougm if (sectype == NULL) 7784653Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 7794653Sdougm else { 7805331Samw if (isdigit((int)*sectype)) { 7815331Samw sa_resource_t resource; 7825331Samw /* 7835331Samw * If sectype[0] is a digit, then it is an index into 7845331Samw * the resource names. We need to find a resource 7855331Samw * record and then get the properties into an 7865331Samw * optionset. The optionset becomes the "node" and the 7875331Samw * rest is hung off of the share. 7885331Samw */ 7895331Samw resource = find_resource_by_index(share, sectype); 7905331Samw if (resource != NULL) { 7915331Samw node = xmlNewChild(resource, NULL, 7925331Samw (xmlChar *)"optionset", NULL); 7935331Samw } else { 7945521Sas200622 /* This shouldn't happen. */ 7955331Samw ret = SA_SYSTEM_ERR; 7965521Sas200622 goto out; 7975331Samw } 7985331Samw } else { 7995331Samw /* 8005331Samw * If not a digit, then it is a security type 8015331Samw * (alternate option space). Security types start with 8025331Samw * an alphabetic. 8035331Samw */ 8045331Samw node = xmlNewChild(root, NULL, (xmlChar *)"security", 8055331Samw NULL); 8065331Samw if (node != NULL) 8075331Samw xmlSetProp(node, (xmlChar *)"sectype", 8085331Samw (xmlChar *)sectype); 8095331Samw } 8104653Sdougm } 8114653Sdougm if (node == NULL) { 8124653Sdougm ret = SA_NO_MEMORY; 8134653Sdougm goto out; 8144653Sdougm } 8154653Sdougm 8164653Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 8174653Sdougm /* now find the properties */ 8183034Sdougm iter = scf_iter_create(handle->handle); 8193034Sdougm value = scf_value_create(handle->handle); 8203034Sdougm prop = scf_property_create(handle->handle); 8213034Sdougm name = malloc(scf_max_name_len); 8223034Sdougm valuestr = malloc(vallen); 8233034Sdougm 8244653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 8254653Sdougm goto out; 8264653Sdougm 8275331Samw /* iterate over the share pg properties */ 8284653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 8294653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 8303034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 8313034Sdougm if (scf_property_get_name(prop, name, 8324653Sdougm scf_max_name_len) > 0) { 8334653Sdougm if (scf_property_get_value(prop, value) == 0) { 8344653Sdougm if (scf_value_get_astring(value, 8354653Sdougm valuestr, vallen) >= 0) { 8364653Sdougm ret = SA_OK; 8374653Sdougm } 8383034Sdougm } 8393034Sdougm } else { 8404653Sdougm ret = SA_SYSTEM_ERR; 8413034Sdougm } 8423034Sdougm if (ret == SA_OK) { 8434653Sdougm sa_property_t prop; 8444653Sdougm prop = sa_create_property(name, valuestr); 8454653Sdougm if (prop != NULL) 8464653Sdougm prop = (sa_property_t)xmlAddChild(node, 8474653Sdougm (xmlNodePtr)prop); 8484653Sdougm else 8494653Sdougm ret = SA_NO_MEMORY; 8503034Sdougm } 8513034Sdougm } 8523034Sdougm } else { 8534653Sdougm ret = SA_SYSTEM_ERR; 8543034Sdougm } 8554653Sdougm out: 8563034Sdougm if (iter != NULL) 8574653Sdougm scf_iter_destroy(iter); 8583034Sdougm if (value != NULL) 8594653Sdougm scf_value_destroy(value); 8603034Sdougm if (prop != NULL) 8614653Sdougm scf_property_destroy(prop); 8623034Sdougm if (name != NULL) 8634653Sdougm free(name); 8643034Sdougm if (valuestr != NULL) 8654653Sdougm free(valuestr); 8663034Sdougm return (ret); 8673034Sdougm } 8683034Sdougm 8693034Sdougm /* 8703034Sdougm * sa_extract_group(root, handle, instance) 8713034Sdougm * 8724653Sdougm * Get the config info for this instance of a group and create the XML 8733034Sdougm * subtree from it. 8743034Sdougm */ 8753034Sdougm 8763034Sdougm static int 8773034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 878*5951Sdougm scf_instance_t *instance, sa_handle_t sahandle) 8793034Sdougm { 8803034Sdougm char *buff; 8813034Sdougm xmlNodePtr node; 8823034Sdougm scf_iter_t *iter; 8833034Sdougm char *proto; 8843034Sdougm char *sectype; 8853034Sdougm int have_shares = 0; 8863034Sdougm int has_proto = 0; 8873034Sdougm int is_default = 0; 8883034Sdougm int ret = SA_OK; 8893034Sdougm int err; 8903034Sdougm 8913034Sdougm buff = malloc(scf_max_name_len); 8924653Sdougm if (buff == NULL) 8934653Sdougm return (SA_NO_MEMORY); 8944653Sdougm 8953034Sdougm iter = scf_iter_create(handle->handle); 8964653Sdougm if (iter == NULL) { 8974653Sdougm ret = SA_NO_MEMORY; 8984653Sdougm goto out; 8994653Sdougm } 9004653Sdougm 9014653Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 9023034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 9034653Sdougm if (node == NULL) { 9044653Sdougm ret = SA_NO_MEMORY; 9054653Sdougm goto out; 9064653Sdougm } 9074653Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 9084653Sdougm if (strcmp(buff, "default") == 0) 9093034Sdougm is_default++; 9104653Sdougm 9114653Sdougm sa_extract_attrs(node, handle, instance); 9124653Sdougm /* 9134653Sdougm * Iterate through all the property groups 9144653Sdougm * looking for those with security or 9154653Sdougm * optionset prefixes. The names of the 9164653Sdougm * matching pgroups are parsed to get the 9174653Sdougm * protocol, and for security, the sectype. 9184653Sdougm * Syntax is as follows: 9194653Sdougm * optionset | optionset_<proto> 9204653Sdougm * security_default | security_<proto>_<sectype> 9214653Sdougm * "operation" is handled by 9224653Sdougm * sa_extract_attrs(). 9234653Sdougm */ 9244653Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 9254653Sdougm ret = SA_NO_MEMORY; 9264653Sdougm goto out; 9274653Sdougm } 9284653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 9294653Sdougm /* Have a pgroup so sort it out */ 9304653Sdougm ret = scf_pg_get_name(handle->pg, buff, 9314653Sdougm scf_max_name_len); 9324653Sdougm if (ret > 0) { 9334653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 9343034Sdougm sa_share_from_pgroup(node, handle, 9354653Sdougm handle->pg, buff); 9363034Sdougm have_shares++; 9374653Sdougm } else if (strncmp(buff, "optionset", 9) == 9384653Sdougm 0) { 9393034Sdougm char *nodetype = "optionset"; 9404653Sdougm /* Have an optionset */ 9413034Sdougm sectype = NULL; 9423034Sdougm proto = strchr(buff, '_'); 9433034Sdougm if (proto != NULL) { 9444653Sdougm *proto++ = '\0'; 9454653Sdougm sectype = strchr(proto, '_'); 9464653Sdougm if (sectype != NULL) { 9474653Sdougm *sectype++ = '\0'; 9484653Sdougm nodetype = "security"; 9494653Sdougm } 9503034Sdougm } 9513034Sdougm ret = sa_extract_pgroup(node, handle, 9524653Sdougm handle->pg, nodetype, proto, 9534653Sdougm sectype); 9543034Sdougm has_proto++; 9554653Sdougm } else if (strncmp(buff, "security", 8) == 0) { 9563034Sdougm /* 9574653Sdougm * Have a security (note that 9583034Sdougm * this should change in the 9593034Sdougm * future) 9603034Sdougm */ 9613034Sdougm proto = strchr(buff, '_'); 9623034Sdougm sectype = NULL; 9633034Sdougm if (proto != NULL) { 9644653Sdougm *proto++ = '\0'; 9654653Sdougm sectype = strchr(proto, '_'); 9664653Sdougm if (sectype != NULL) 9674653Sdougm *sectype++ = '\0'; 9684653Sdougm if (strcmp(proto, "default") == 9694653Sdougm 0) 9704653Sdougm proto = NULL; 9713034Sdougm } 9723034Sdougm ret = sa_extract_pgroup(node, handle, 9734653Sdougm handle->pg, "security", proto, 9744653Sdougm sectype); 9753034Sdougm has_proto++; 9763034Sdougm } 9774653Sdougm /* Ignore everything else */ 9783034Sdougm } 9794653Sdougm } 9804653Sdougm /* 9814653Sdougm * Make sure we have a valid default group. 9824653Sdougm * On first boot, default won't have any 9834653Sdougm * protocols defined and won't be enabled (but 9844653Sdougm * should be). 9854653Sdougm */ 9864653Sdougm if (is_default) { 9874653Sdougm char *state = sa_get_group_attr((sa_group_t)node, 9884653Sdougm "state"); 9894653Sdougm char **protos; 9904653Sdougm int numprotos; 9914653Sdougm int i; 9923034Sdougm 9934653Sdougm if (state == NULL) { 9943034Sdougm /* set attribute to enabled */ 9953034Sdougm (void) sa_set_group_attr((sa_group_t)node, 9964653Sdougm "state", "enabled"); 9974653Sdougm /* We can assume no protocols */ 9983034Sdougm numprotos = sa_get_protocols(&protos); 9993034Sdougm for (i = 0; i < numprotos; i++) 10004653Sdougm (void) sa_create_optionset( 10014653Sdougm (sa_group_t)node, protos[i]); 10023034Sdougm if (numprotos > 0) 10034653Sdougm free(protos); 10044653Sdougm } else { 10053034Sdougm sa_free_attr_string(state); 10063034Sdougm } 10074653Sdougm } 10084653Sdougm /* Do a second pass if shares were found */ 10094653Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 10104653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 10113034Sdougm /* 10124653Sdougm * Have a pgroup so see if it is a 10133034Sdougm * share optionset 10143034Sdougm */ 10153034Sdougm err = scf_pg_get_name(handle->pg, buff, 10164653Sdougm scf_max_name_len); 10174653Sdougm if (err <= 0) 10184653Sdougm continue; 10194653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 10203034Sdougm ret = sa_share_props_from_pgroup(node, 10214653Sdougm handle, handle->pg, buff, 10224653Sdougm sahandle); 10233034Sdougm } 10243034Sdougm } 10253034Sdougm } 10263034Sdougm } 10274653Sdougm out: 10283034Sdougm if (iter != NULL) 10294653Sdougm scf_iter_destroy(iter); 10303034Sdougm if (buff != NULL) 10314653Sdougm free(buff); 10323034Sdougm return (ret); 10333034Sdougm } 10343034Sdougm 10353034Sdougm /* 10363034Sdougm * sa_extract_defaults(root, handle, instance) 10373034Sdougm * 10384653Sdougm * Local function to find the default properties that live in the 10395331Samw * default instance's "operation" property group. 10403034Sdougm */ 10413034Sdougm 10423034Sdougm static void 10433034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 10443034Sdougm scf_instance_t *instance) 10453034Sdougm { 10463034Sdougm xmlNodePtr node; 10473034Sdougm scf_property_t *prop; 10483034Sdougm scf_value_t *value; 10493034Sdougm char *valuestr; 10503034Sdougm ssize_t vallen; 10513034Sdougm 10523034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 10533034Sdougm prop = scf_property_create(handle->handle); 10543034Sdougm value = scf_value_create(handle->handle); 10553034Sdougm valuestr = malloc(vallen); 10564653Sdougm 10574653Sdougm if (prop == NULL || value == NULL || vallen == 0 || 10584653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 10594653Sdougm goto out; 10604653Sdougm 10614653Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 10624653Sdougm goto out; 10634653Sdougm 10644653Sdougm /* Found the property so get the value */ 10654653Sdougm if (scf_property_get_value(prop, value) == 0) { 10664653Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 10673034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 10684653Sdougm NULL); 10693034Sdougm if (node != NULL) { 10704653Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 10714653Sdougm (xmlChar *)valuestr); 10724653Sdougm xmlSetProp(node, (xmlChar *)"path", 10734653Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 10743034Sdougm } 10753034Sdougm } 10763034Sdougm } 10774653Sdougm out: 10783034Sdougm if (valuestr != NULL) 10794653Sdougm free(valuestr); 10803034Sdougm if (value != NULL) 10814653Sdougm scf_value_destroy(value); 10823034Sdougm if (prop != NULL) 10834653Sdougm scf_property_destroy(prop); 10843034Sdougm } 10853034Sdougm 10863034Sdougm 10873034Sdougm /* 10885331Samw * sa_get_config(handle, root, doc, sahandle) 10893034Sdougm * 10904653Sdougm * Walk the SMF repository for /network/shares/group and find all the 10913034Sdougm * instances. These become group names. Then add the XML structure 10923034Sdougm * below the groups based on property groups and properties. 10933034Sdougm */ 10943034Sdougm int 10953973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 10963034Sdougm { 10973034Sdougm int ret = SA_OK; 10983034Sdougm scf_instance_t *instance; 10993034Sdougm scf_iter_t *iter; 11003034Sdougm char buff[BUFSIZ * 2]; 11013034Sdougm 11023034Sdougm instance = scf_instance_create(handle->handle); 11033034Sdougm iter = scf_iter_create(handle->handle); 11043973Sdougm if (instance != NULL && iter != NULL) { 11054653Sdougm if ((ret = scf_iter_service_instances(iter, 11064653Sdougm handle->service)) == 0) { 11074653Sdougm while ((ret = scf_iter_next_instance(iter, 11084653Sdougm instance)) > 0) { 11094653Sdougm if (scf_instance_get_name(instance, buff, 11104653Sdougm sizeof (buff)) > 0) { 11114653Sdougm if (strcmp(buff, "default") == 0) 11124653Sdougm sa_extract_defaults(root, 11134653Sdougm handle, instance); 11144653Sdougm ret = sa_extract_group(root, handle, 11154653Sdougm instance, sahandle); 11164653Sdougm } 11174653Sdougm } 11183034Sdougm } 11193034Sdougm } 11203973Sdougm 11214653Sdougm /* Always cleanup these */ 11223034Sdougm if (instance != NULL) 11234653Sdougm scf_instance_destroy(instance); 11243034Sdougm if (iter != NULL) 11254653Sdougm scf_iter_destroy(iter); 11263034Sdougm return (ret); 11273034Sdougm } 11283034Sdougm 11293034Sdougm /* 11303034Sdougm * sa_get_instance(handle, instance) 11313034Sdougm * 11324653Sdougm * Get the instance of the group service. This is actually the 11333034Sdougm * specific group name. The instance is needed for all property and 11343034Sdougm * control operations. 11353034Sdougm */ 11363034Sdougm 11373034Sdougm int 11383034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 11393034Sdougm { 11403034Sdougm if (scf_service_get_instance(handle->service, instname, 11414653Sdougm handle->instance) != 0) { 11424653Sdougm return (SA_NO_SUCH_GROUP); 11433034Sdougm } 11443034Sdougm return (SA_OK); 11453034Sdougm } 11463034Sdougm 11473034Sdougm /* 11483034Sdougm * sa_create_instance(handle, instname) 11493034Sdougm * 11503034Sdougm * Create a new SMF service instance. There can only be one with a 11513034Sdougm * given name. 11523034Sdougm */ 11533034Sdougm 11543034Sdougm int 11553034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 11563034Sdougm { 11573034Sdougm int ret = SA_OK; 11583034Sdougm char instance[SA_GROUP_INST_LEN]; 11593034Sdougm if (scf_service_add_instance(handle->service, instname, 11604653Sdougm handle->instance) != 0) { 11613034Sdougm /* better error returns need to be added based on real error */ 11624653Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 11634653Sdougm ret = SA_NO_PERMISSION; 11644653Sdougm else 11654653Sdougm ret = SA_DUPLICATE_NAME; 11663034Sdougm } else { 11674653Sdougm /* have the service created, so enable it */ 11684653Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 11694653Sdougm SA_SVC_FMRI_BASE, instname); 11704653Sdougm (void) smf_enable_instance(instance, 0); 11713034Sdougm } 11723034Sdougm return (ret); 11733034Sdougm } 11743034Sdougm 11753034Sdougm /* 11763034Sdougm * sa_delete_instance(handle, instname) 11773034Sdougm * 11783034Sdougm * When a group goes away, we also remove the service instance. 11793034Sdougm */ 11803034Sdougm 11813034Sdougm int 11823034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 11833034Sdougm { 11843034Sdougm int ret; 11853034Sdougm 11863034Sdougm if (strcmp(instname, "default") == 0) { 11874653Sdougm ret = SA_NO_PERMISSION; 11883034Sdougm } else { 11894653Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 11904653Sdougm if (scf_instance_delete(handle->instance) != 0) 11914653Sdougm /* need better analysis */ 11924653Sdougm ret = SA_NO_PERMISSION; 11934653Sdougm } 11943034Sdougm } 11953034Sdougm return (ret); 11963034Sdougm } 11973034Sdougm 11983034Sdougm /* 11993034Sdougm * sa_create_pgroup(handle, pgroup) 12003034Sdougm * 12013034Sdougm * create a new property group 12023034Sdougm */ 12033034Sdougm 12043034Sdougm int 12053034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 12063034Sdougm { 12073034Sdougm int ret = SA_OK; 1208*5951Sdougm int persist = 0; 1209*5951Sdougm 12103034Sdougm /* 12114653Sdougm * Only create a handle if it doesn't exist. It is ok to exist 12123034Sdougm * since the pg handle will be set as a side effect. 12133034Sdougm */ 12144653Sdougm if (handle->pg == NULL) 12154653Sdougm handle->pg = scf_pg_create(handle->handle); 12164653Sdougm 12173034Sdougm /* 1218*5951Sdougm * Special case for a non-persistent property group. This is 1219*5951Sdougm * internal use only. 1220*5951Sdougm */ 1221*5951Sdougm if (*pgroup == '*') { 1222*5951Sdougm persist = SCF_PG_FLAG_NONPERSISTENT; 1223*5951Sdougm pgroup++; 1224*5951Sdougm } 1225*5951Sdougm 1226*5951Sdougm /* 12274653Sdougm * If the pgroup exists, we are done. If it doesn't, then we 12283034Sdougm * need to actually add one to the service instance. 12293034Sdougm */ 12303034Sdougm if (scf_instance_get_pg(handle->instance, 12314653Sdougm pgroup, handle->pg) != 0) { 1232*5951Sdougm 12334653Sdougm /* Doesn't exist so create one */ 12344653Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 1235*5951Sdougm SCF_GROUP_APPLICATION, persist, handle->pg) != 0) { 12364653Sdougm switch (scf_error()) { 12374653Sdougm case SCF_ERROR_PERMISSION_DENIED: 12384653Sdougm ret = SA_NO_PERMISSION; 12394653Sdougm break; 12404653Sdougm default: 12414653Sdougm ret = SA_SYSTEM_ERR; 12424653Sdougm break; 12434653Sdougm } 12443034Sdougm } 12453034Sdougm } 12463034Sdougm return (ret); 12473034Sdougm } 12483034Sdougm 12493034Sdougm /* 12503034Sdougm * sa_delete_pgroup(handle, pgroup) 12513034Sdougm * 12524653Sdougm * Remove the property group from the current instance of the service, 12533034Sdougm * but only if it actually exists. 12543034Sdougm */ 12553034Sdougm 12563034Sdougm int 12573034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 12583034Sdougm { 12593034Sdougm int ret = SA_OK; 12603034Sdougm /* 12614653Sdougm * Only delete if it does exist. 12623034Sdougm */ 12634653Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 12644653Sdougm /* does exist so delete it */ 12654653Sdougm if (scf_pg_delete(handle->pg) != 0) 12664653Sdougm ret = SA_SYSTEM_ERR; 12674653Sdougm } else { 12683034Sdougm ret = SA_SYSTEM_ERR; 12693034Sdougm } 12703034Sdougm if (ret == SA_SYSTEM_ERR && 12713034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 12723034Sdougm ret = SA_NO_PERMISSION; 12733034Sdougm } 12743034Sdougm return (ret); 12753034Sdougm } 12763034Sdougm 12773034Sdougm /* 12783034Sdougm * sa_start_transaction(handle, pgroup) 12793034Sdougm * 12803034Sdougm * Start an SMF transaction so we can deal with properties. it would 12813034Sdougm * be nice to not have to expose this, but we have to in order to 12823034Sdougm * optimize. 12833034Sdougm * 12843034Sdougm * Basic model is to hold the transaction in the handle and allow 12853034Sdougm * property adds/deletes/updates to be added then close the 12863034Sdougm * transaction (or abort). There may eventually be a need to handle 12873034Sdougm * other types of transaction mechanisms but we don't do that now. 12883034Sdougm * 12893034Sdougm * An sa_start_transaction must be followed by either an 12903034Sdougm * sa_end_transaction or sa_abort_transaction before another 12913034Sdougm * sa_start_transaction can be done. 12923034Sdougm */ 12933034Sdougm 12943034Sdougm int 12953034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 12963034Sdougm { 12973034Sdougm int ret = SA_OK; 12983034Sdougm /* 12994653Sdougm * Lookup the property group and create it if it doesn't already 13003034Sdougm * exist. 13013034Sdougm */ 1302*5951Sdougm if (handle == NULL) 1303*5951Sdougm return (SA_CONFIG_ERR); 1304*5951Sdougm 13053034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 13064653Sdougm ret = sa_create_pgroup(handle, propgroup); 13074653Sdougm if (ret == SA_OK) { 13084653Sdougm handle->trans = scf_transaction_create(handle->handle); 13094653Sdougm if (handle->trans != NULL) { 13104653Sdougm if (scf_transaction_start(handle->trans, 13114653Sdougm handle->pg) != 0) { 13124653Sdougm ret = SA_SYSTEM_ERR; 13134653Sdougm } 13144653Sdougm if (ret != SA_OK) { 13154653Sdougm scf_transaction_destroy(handle->trans); 13164653Sdougm handle->trans = NULL; 13174653Sdougm } 13184653Sdougm } else { 13194653Sdougm ret = SA_SYSTEM_ERR; 13204653Sdougm } 13213034Sdougm } 13223034Sdougm } 13233034Sdougm if (ret == SA_SYSTEM_ERR && 13243034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 13253034Sdougm ret = SA_NO_PERMISSION; 13263034Sdougm } 13273034Sdougm return (ret); 13283034Sdougm } 13293034Sdougm 1330*5951Sdougm 13313034Sdougm /* 1332*5951Sdougm * sa_end_transaction(scfhandle, sahandle) 13333034Sdougm * 13343034Sdougm * Commit the changes that were added to the transaction in the 13353034Sdougm * handle. Do all necessary cleanup. 13363034Sdougm */ 13373034Sdougm 13383034Sdougm int 1339*5951Sdougm sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle) 13403034Sdougm { 13413034Sdougm int ret = SA_OK; 13423034Sdougm 1343*5951Sdougm if (handle == NULL || handle->trans == NULL || sahandle == NULL) { 13444653Sdougm ret = SA_SYSTEM_ERR; 13453034Sdougm } else { 13464653Sdougm if (scf_transaction_commit(handle->trans) < 0) 13474653Sdougm ret = SA_SYSTEM_ERR; 13484653Sdougm scf_transaction_destroy_children(handle->trans); 13494653Sdougm scf_transaction_destroy(handle->trans); 1350*5951Sdougm if (ret == SA_OK) 1351*5951Sdougm set_transaction_tstamp(sahandle); 13524653Sdougm handle->trans = NULL; 13533034Sdougm } 13543034Sdougm return (ret); 13553034Sdougm } 13563034Sdougm 13573034Sdougm /* 13583034Sdougm * sa_abort_transaction(handle) 13593034Sdougm * 13603034Sdougm * Abort the changes that were added to the transaction in the 13613034Sdougm * handle. Do all necessary cleanup. 13623034Sdougm */ 13633034Sdougm 13643034Sdougm void 13653034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 13663034Sdougm { 13673034Sdougm if (handle->trans != NULL) { 13684653Sdougm scf_transaction_reset_all(handle->trans); 13694653Sdougm scf_transaction_destroy_children(handle->trans); 13704653Sdougm scf_transaction_destroy(handle->trans); 13714653Sdougm handle->trans = NULL; 13723034Sdougm } 13733034Sdougm } 13743034Sdougm 13753034Sdougm /* 1376*5951Sdougm * set_transaction_tstamp(sahandle) 1377*5951Sdougm * 1378*5951Sdougm * After a successful transaction commit, update the timestamp of the 1379*5951Sdougm * last transaction. This lets us detect changes from other processes. 1380*5951Sdougm */ 1381*5951Sdougm static void 1382*5951Sdougm set_transaction_tstamp(sa_handle_impl_t sahandle) 1383*5951Sdougm { 1384*5951Sdougm char tstring[32]; 1385*5951Sdougm struct timeval tv; 1386*5951Sdougm scfutilhandle_t *scfhandle; 1387*5951Sdougm 1388*5951Sdougm if (sahandle == NULL || sahandle->scfhandle == NULL) 1389*5951Sdougm return; 1390*5951Sdougm 1391*5951Sdougm scfhandle = sahandle->scfhandle; 1392*5951Sdougm 1393*5951Sdougm if (sa_get_instance(scfhandle, "default") != SA_OK) 1394*5951Sdougm return; 1395*5951Sdougm 1396*5951Sdougm if (gettimeofday(&tv, NULL) != 0) 1397*5951Sdougm return; 1398*5951Sdougm 1399*5951Sdougm if (sa_start_transaction(scfhandle, "*state") != SA_OK) 1400*5951Sdougm return; 1401*5951Sdougm 1402*5951Sdougm sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv)); 1403*5951Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans); 1404*5951Sdougm if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) == 1405*5951Sdougm SA_OK) { 1406*5951Sdougm /* 1407*5951Sdougm * While best if it succeeds, a failure doesn't cause 1408*5951Sdougm * problems and we will ignore it anyway. 1409*5951Sdougm */ 1410*5951Sdougm (void) scf_transaction_commit(scfhandle->trans); 1411*5951Sdougm scf_transaction_destroy_children(scfhandle->trans); 1412*5951Sdougm scf_transaction_destroy(scfhandle->trans); 1413*5951Sdougm } else { 1414*5951Sdougm sa_abort_transaction(scfhandle); 1415*5951Sdougm } 1416*5951Sdougm } 1417*5951Sdougm 1418*5951Sdougm /* 14193034Sdougm * sa_set_property(handle, prop, value) 14203034Sdougm * 14214653Sdougm * Set a property transaction entry into the pending SMF transaction. 14223034Sdougm */ 14233034Sdougm 14243034Sdougm int 14253034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 14263034Sdougm { 14273034Sdougm int ret = SA_OK; 14283034Sdougm scf_value_t *value; 14293034Sdougm scf_transaction_entry_t *entry; 14303034Sdougm /* 14314653Sdougm * Properties must be set in transactions and don't take 14323034Sdougm * effect until the transaction has been ended/committed. 14333034Sdougm */ 14343034Sdougm value = scf_value_create(handle->handle); 14353034Sdougm entry = scf_entry_create(handle->handle); 14363034Sdougm if (value != NULL && entry != NULL) { 14374653Sdougm if (scf_transaction_property_change(handle->trans, entry, 14384653Sdougm propname, SCF_TYPE_ASTRING) == 0 || 14394653Sdougm scf_transaction_property_new(handle->trans, entry, 14404653Sdougm propname, SCF_TYPE_ASTRING) == 0) { 14414653Sdougm if (scf_value_set_astring(value, valstr) == 0) { 14424653Sdougm if (scf_entry_add_value(entry, value) != 0) { 14434653Sdougm ret = SA_SYSTEM_ERR; 14444653Sdougm scf_value_destroy(value); 14454653Sdougm } 14464653Sdougm /* The value is in the transaction */ 14474653Sdougm value = NULL; 14484653Sdougm } else { 14494653Sdougm /* Value couldn't be constructed */ 14504653Sdougm ret = SA_SYSTEM_ERR; 14514653Sdougm } 14524653Sdougm /* The entry is in the transaction */ 14534653Sdougm entry = NULL; 14544653Sdougm } else { 14553034Sdougm ret = SA_SYSTEM_ERR; 14563034Sdougm } 14574653Sdougm } else { 14583034Sdougm ret = SA_SYSTEM_ERR; 14593034Sdougm } 14603034Sdougm if (ret == SA_SYSTEM_ERR) { 14614653Sdougm switch (scf_error()) { 14624653Sdougm case SCF_ERROR_PERMISSION_DENIED: 14634653Sdougm ret = SA_NO_PERMISSION; 14644653Sdougm break; 14654653Sdougm } 14663034Sdougm } 14673034Sdougm /* 14684653Sdougm * Cleanup if there were any errors that didn't leave these 14693034Sdougm * values where they would be cleaned up later. 14703034Sdougm */ 14713034Sdougm if (value != NULL) 14724653Sdougm scf_value_destroy(value); 14733034Sdougm if (entry != NULL) 14744653Sdougm scf_entry_destroy(entry); 14753034Sdougm return (ret); 14763034Sdougm } 14773034Sdougm 14783034Sdougm /* 14795331Samw * check_resource(share) 14805331Samw * 14815331Samw * Check to see if share has any persistent resources. We don't want 14825331Samw * to save if they are all transient. 14835331Samw */ 14845331Samw static int 14855331Samw check_resource(sa_share_t share) 14865331Samw { 14875331Samw sa_resource_t resource; 14885331Samw int ret = B_FALSE; 14895331Samw 14905331Samw for (resource = sa_get_share_resource(share, NULL); 14915331Samw resource != NULL && ret == B_FALSE; 14925331Samw resource = sa_get_next_resource(resource)) { 14935331Samw char *type; 14945331Samw type = sa_get_resource_attr(resource, "type"); 14955331Samw if (type != NULL) { 14965331Samw if (strcmp(type, "transient") != 0) { 14975331Samw ret = B_TRUE; 14985331Samw } 14995331Samw sa_free_attr_string(type); 15005331Samw } 15015331Samw } 15025331Samw return (ret); 15035331Samw } 15045331Samw 15055331Samw /* 15065331Samw * sa_set_resource_property(handle, prop, value) 15075331Samw * 15085331Samw * set a property transaction entry into the pending SMF 15095331Samw * transaction. We don't want to include any transient resources 15105331Samw */ 15115331Samw 15125331Samw static int 15135331Samw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 15145331Samw { 15155331Samw int ret = SA_OK; 15165331Samw scf_value_t *value; 15175331Samw scf_transaction_entry_t *entry; 15185331Samw sa_resource_t resource; 15195331Samw char *valstr; 15205331Samw char *idstr; 15215331Samw char *description; 15225331Samw char *propstr = NULL; 15235331Samw size_t strsize; 15245331Samw 15255331Samw /* don't bother if no persistent resources */ 15265331Samw if (check_resource(share) == B_FALSE) 15275331Samw return (ret); 15285331Samw 15295331Samw /* 15305331Samw * properties must be set in transactions and don't take 15315331Samw * effect until the transaction has been ended/committed. 15325331Samw */ 15335331Samw entry = scf_entry_create(handle->handle); 15345331Samw if (entry == NULL) 15355331Samw return (SA_SYSTEM_ERR); 15365331Samw 15375331Samw if (scf_transaction_property_change(handle->trans, entry, 15385331Samw "resource", SCF_TYPE_ASTRING) != 0 && 15395331Samw scf_transaction_property_new(handle->trans, entry, 15405331Samw "resource", SCF_TYPE_ASTRING) != 0) { 15415331Samw scf_entry_destroy(entry); 15425331Samw return (SA_SYSTEM_ERR); 15435331Samw 15445331Samw } 15455331Samw for (resource = sa_get_share_resource(share, NULL); 15465331Samw resource != NULL; 15475331Samw resource = sa_get_next_resource(resource)) { 15485331Samw value = scf_value_create(handle->handle); 15495331Samw if (value == NULL) { 15505331Samw ret = SA_NO_MEMORY; 15515331Samw break; 15525331Samw } 15535331Samw /* Get size of complete string */ 15545331Samw valstr = sa_get_resource_attr(resource, "name"); 15555331Samw idstr = sa_get_resource_attr(resource, "id"); 15565331Samw description = sa_get_resource_description(resource); 15575331Samw strsize = (valstr != NULL) ? strlen(valstr) : 0; 15585331Samw strsize += (idstr != NULL) ? strlen(idstr) : 0; 15595331Samw strsize += (description != NULL) ? strlen(description) : 0; 15605331Samw if (strsize > 0) { 15615331Samw strsize += 3; /* add nul and ':' */ 15625331Samw propstr = (char *)malloc(strsize); 15635331Samw if (propstr == NULL) { 15645331Samw scf_value_destroy(value); 15655331Samw ret = SA_NO_MEMORY; 15665331Samw goto err; 15675331Samw } 15685331Samw if (idstr == NULL) 15695331Samw (void) snprintf(propstr, strsize, "%s", 15705331Samw valstr ? valstr : ""); 15715331Samw else 15725331Samw (void) snprintf(propstr, strsize, "%s:%s:%s", 15735331Samw idstr ? idstr : "", valstr ? valstr : "", 15745331Samw description ? description : ""); 15755331Samw if (scf_value_set_astring(value, propstr) != 0) { 15765331Samw ret = SA_SYSTEM_ERR; 15775331Samw free(propstr); 15785331Samw scf_value_destroy(value); 15795331Samw break; 15805331Samw } 15815331Samw if (scf_entry_add_value(entry, value) != 0) { 15825331Samw ret = SA_SYSTEM_ERR; 15835331Samw free(propstr); 15845331Samw scf_value_destroy(value); 15855331Samw break; 15865331Samw } 15875331Samw /* the value is in the transaction */ 15885331Samw value = NULL; 15895331Samw free(propstr); 15905331Samw } 15915331Samw err: 15925331Samw if (valstr != NULL) 15935331Samw sa_free_attr_string(valstr); 15945331Samw if (idstr != NULL) 15955331Samw sa_free_attr_string(idstr); 15965331Samw if (description != NULL) 15975331Samw sa_free_share_description(description); 15985331Samw } 15995331Samw /* the entry is in the transaction */ 16005331Samw entry = NULL; 16015331Samw 16025331Samw if (ret == SA_SYSTEM_ERR) { 16035331Samw switch (scf_error()) { 16045331Samw case SCF_ERROR_PERMISSION_DENIED: 16055331Samw ret = SA_NO_PERMISSION; 16065331Samw break; 16075331Samw } 16085331Samw } 16095331Samw /* 16105331Samw * cleanup if there were any errors that didn't leave 16115331Samw * these values where they would be cleaned up later. 16125331Samw */ 16135331Samw if (entry != NULL) 16145331Samw scf_entry_destroy(entry); 16155331Samw 16165331Samw return (ret); 16175331Samw } 16185331Samw 16195331Samw /* 16203034Sdougm * sa_commit_share(handle, group, share) 16213034Sdougm * 16224653Sdougm * Commit this share to the repository. 16233034Sdougm * properties are added if they exist but can be added later. 16243034Sdougm * Need to add to dfstab and sharetab, if appropriate. 16253034Sdougm */ 16263034Sdougm int 16273034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 16283034Sdougm { 16293034Sdougm int ret = SA_OK; 16303034Sdougm char *groupname; 16313034Sdougm char *name; 16323034Sdougm char *description; 16333034Sdougm char *sharename; 16343034Sdougm ssize_t proplen; 16353034Sdougm char *propstring; 16363034Sdougm 16373034Sdougm /* 16384653Sdougm * Don't commit in the zfs group. We do commit legacy 16393034Sdougm * (default) and all other groups/shares. ZFS is handled 16403034Sdougm * through the ZFS configuration rather than SMF. 16413034Sdougm */ 16423034Sdougm 16433034Sdougm groupname = sa_get_group_attr(group, "name"); 16443034Sdougm if (groupname != NULL) { 16454653Sdougm if (strcmp(groupname, "zfs") == 0) { 16464653Sdougm /* 16474653Sdougm * Adding to the ZFS group will result in the sharenfs 16484653Sdougm * property being set but we don't want to do anything 16494653Sdougm * SMF related at this point. 16504653Sdougm */ 16514653Sdougm sa_free_attr_string(groupname); 16524653Sdougm return (ret); 16534653Sdougm } 16543034Sdougm } 16553034Sdougm 16563034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 16573034Sdougm propstring = malloc(proplen); 16583034Sdougm if (propstring == NULL) 16594653Sdougm ret = SA_NO_MEMORY; 16603034Sdougm 16613034Sdougm if (groupname != NULL && ret == SA_OK) { 16624653Sdougm ret = sa_get_instance(handle, groupname); 16634653Sdougm sa_free_attr_string(groupname); 16644653Sdougm groupname = NULL; 16654653Sdougm sharename = sa_get_share_attr(share, "id"); 16664653Sdougm if (sharename == NULL) { 16674653Sdougm /* slipped by */ 16684653Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 16694653Sdougm generate_unique_sharename(shname); 16704653Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 16713034Sdougm (xmlChar *)shname); 16724653Sdougm sharename = strdup(shname); 16733034Sdougm } 16744653Sdougm if (sharename != NULL) { 16754653Sdougm sigset_t old, new; 16764653Sdougm /* 16774653Sdougm * Have a share name allocated so create a pgroup for 16784653Sdougm * it. It may already exist, but that is OK. In order 16794653Sdougm * to avoid creating a share pgroup that doesn't have 16804653Sdougm * a path property, block signals around the critical 16814653Sdougm * region of creating the share pgroup and props. 16824653Sdougm */ 16834653Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 16844653Sdougm (void) sigaddset(&new, SIGHUP); 16854653Sdougm (void) sigaddset(&new, SIGINT); 16864653Sdougm (void) sigaddset(&new, SIGQUIT); 16874653Sdougm (void) sigaddset(&new, SIGTSTP); 16884653Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 16894653Sdougm 16904653Sdougm ret = sa_create_pgroup(handle, sharename); 16914653Sdougm if (ret == SA_OK) { 16924653Sdougm /* 16934653Sdougm * Now start the transaction for the 16944653Sdougm * properties that define this share. They may 16954653Sdougm * exist so attempt to update before create. 16964653Sdougm */ 16974653Sdougm ret = sa_start_transaction(handle, sharename); 16984653Sdougm } 16994653Sdougm if (ret == SA_OK) { 17004653Sdougm name = sa_get_share_attr(share, "path"); 17014653Sdougm if (name != NULL) { 17024653Sdougm /* 17034653Sdougm * There needs to be a path 17044653Sdougm * for a share to exist. 17054653Sdougm */ 17064653Sdougm ret = sa_set_property(handle, "path", 17074653Sdougm name); 17084653Sdougm sa_free_attr_string(name); 17094653Sdougm } else { 17104653Sdougm ret = SA_NO_MEMORY; 17114653Sdougm } 17124653Sdougm } 17134653Sdougm if (ret == SA_OK) { 17145331Samw name = sa_get_share_attr(share, "drive-letter"); 17155331Samw if (name != NULL) { 17165331Samw /* A drive letter may exist for SMB */ 17174653Sdougm ret = sa_set_property(handle, 17185331Samw "drive-letter", name); 17195331Samw sa_free_attr_string(name); 17204653Sdougm } 17214653Sdougm } 17224653Sdougm if (ret == SA_OK) { 17235331Samw name = sa_get_share_attr(share, "exclude"); 17245331Samw if (name != NULL) { 17255331Samw /* 17265331Samw * In special cases need to 17275331Samw * exclude proto enable. 17285331Samw */ 17295331Samw ret = sa_set_property(handle, 17305331Samw "exclude", name); 17315331Samw sa_free_attr_string(name); 17325331Samw } 17335331Samw } 17345331Samw if (ret == SA_OK) { 17355331Samw /* 17365331Samw * If there are resource names, bundle them up 17375331Samw * and save appropriately. 17385331Samw */ 17395331Samw ret = sa_set_resource_property(handle, share); 17405331Samw } 17415331Samw 17425331Samw if (ret == SA_OK) { 17434653Sdougm description = sa_get_share_description(share); 17444653Sdougm if (description != NULL) { 17454653Sdougm ret = sa_set_property(handle, 17464653Sdougm "description", 17474653Sdougm description); 17484653Sdougm sa_free_share_description(description); 17494653Sdougm } 17504653Sdougm } 17514653Sdougm /* Make sure we cleanup the transaction */ 17524653Sdougm if (ret == SA_OK) { 1753*5951Sdougm sa_handle_impl_t sahandle; 1754*5951Sdougm sahandle = (sa_handle_impl_t) 1755*5951Sdougm sa_find_group_handle(group); 1756*5951Sdougm if (sahandle != NULL) 1757*5951Sdougm ret = sa_end_transaction(handle, 1758*5951Sdougm sahandle); 1759*5951Sdougm else 1760*5951Sdougm ret = SA_SYSTEM_ERR; 17614653Sdougm } else { 17624653Sdougm sa_abort_transaction(handle); 17634653Sdougm } 17644653Sdougm 17654653Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 17664653Sdougm 17674653Sdougm free(sharename); 17683034Sdougm } 17693034Sdougm } 17703034Sdougm if (ret == SA_SYSTEM_ERR) { 17714653Sdougm int err = scf_error(); 17724653Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 17734653Sdougm ret = SA_NO_PERMISSION; 17743034Sdougm } 17753034Sdougm if (propstring != NULL) 17764653Sdougm free(propstring); 17773034Sdougm if (groupname != NULL) 17784653Sdougm sa_free_attr_string(groupname); 17793034Sdougm 17803034Sdougm return (ret); 17813034Sdougm } 17823034Sdougm 17833034Sdougm /* 17845331Samw * remove_resources(handle, share, shareid) 17855331Samw * 17865331Samw * If the share has resources, remove all of them and their 17875331Samw * optionsets. 17885331Samw */ 17895331Samw static int 17905331Samw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 17915331Samw { 17925331Samw sa_resource_t resource; 17935331Samw sa_optionset_t opt; 17945331Samw char *proto; 17955331Samw char *id; 17965331Samw ssize_t proplen; 17975331Samw char *propstring; 17985331Samw int ret = SA_OK; 17995331Samw 18005331Samw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 18015331Samw propstring = malloc(proplen); 18025331Samw if (propstring == NULL) 18035331Samw return (SA_NO_MEMORY); 18045331Samw 18055331Samw for (resource = sa_get_share_resource(share, NULL); 18065331Samw resource != NULL; resource = sa_get_next_resource(resource)) { 18075331Samw id = sa_get_resource_attr(resource, "id"); 18085331Samw if (id == NULL) 18095331Samw continue; 18105331Samw for (opt = sa_get_optionset(resource, NULL); 18115331Samw opt != NULL; opt = sa_get_next_optionset(resource)) { 18125331Samw proto = sa_get_optionset_attr(opt, "type"); 18135331Samw if (proto != NULL) { 18145331Samw (void) snprintf(propstring, proplen, 18155331Samw "%s_%s_%s", shareid, proto, id); 18165331Samw ret = sa_delete_pgroup(handle, propstring); 18175331Samw sa_free_attr_string(proto); 18185331Samw } 18195331Samw } 18205331Samw sa_free_attr_string(id); 18215331Samw } 18225331Samw free(propstring); 18235331Samw return (ret); 18245331Samw } 18255331Samw 18265331Samw /* 18273034Sdougm * sa_delete_share(handle, group, share) 18283034Sdougm * 18294653Sdougm * Remove the specified share from the group (and service instance). 18303034Sdougm */ 18313034Sdougm 18323034Sdougm int 18333034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 18343034Sdougm { 18353034Sdougm int ret = SA_OK; 18363034Sdougm char *groupname = NULL; 18373034Sdougm char *shareid = NULL; 18383034Sdougm sa_optionset_t opt; 18393034Sdougm sa_security_t sec; 18403034Sdougm ssize_t proplen; 18413034Sdougm char *propstring; 18423034Sdougm 18433034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 18443034Sdougm propstring = malloc(proplen); 18453034Sdougm if (propstring == NULL) 18464653Sdougm ret = SA_NO_MEMORY; 18473034Sdougm 18483034Sdougm if (ret == SA_OK) { 18494653Sdougm groupname = sa_get_group_attr(group, "name"); 18504653Sdougm shareid = sa_get_share_attr(share, "id"); 18514653Sdougm if (groupname == NULL || shareid == NULL) { 18524653Sdougm ret = SA_CONFIG_ERR; 18534653Sdougm goto out; 18544653Sdougm } 18553034Sdougm ret = sa_get_instance(handle, groupname); 18563034Sdougm if (ret == SA_OK) { 18575331Samw /* If a share has resources, remove them */ 18585331Samw ret = remove_resources(handle, share, shareid); 18594653Sdougm /* If a share has properties, remove them */ 18604653Sdougm ret = sa_delete_pgroup(handle, shareid); 18614653Sdougm for (opt = sa_get_optionset(share, NULL); 18624653Sdougm opt != NULL; 18634653Sdougm opt = sa_get_next_optionset(opt)) { 18644653Sdougm char *proto; 18654653Sdougm proto = sa_get_optionset_attr(opt, "type"); 18664653Sdougm if (proto != NULL) { 18674653Sdougm (void) snprintf(propstring, 18684653Sdougm proplen, "%s_%s", shareid, 18694653Sdougm proto); 18704653Sdougm ret = sa_delete_pgroup(handle, 18714653Sdougm propstring); 18724653Sdougm sa_free_attr_string(proto); 18734653Sdougm } else { 18744653Sdougm ret = SA_NO_MEMORY; 18754653Sdougm } 18763034Sdougm } 18773034Sdougm /* 18784653Sdougm * If a share has security/negotiable 18793034Sdougm * properties, remove them. 18803034Sdougm */ 18814653Sdougm for (sec = sa_get_security(share, NULL, NULL); 18824653Sdougm sec != NULL; 18834653Sdougm sec = sa_get_next_security(sec)) { 18844653Sdougm char *proto; 18854653Sdougm char *sectype; 18864653Sdougm proto = sa_get_security_attr(sec, "type"); 18874653Sdougm sectype = sa_get_security_attr(sec, "sectype"); 18884653Sdougm if (proto != NULL && sectype != NULL) { 18894653Sdougm (void) snprintf(propstring, proplen, 18904653Sdougm "%s_%s_%s", shareid, proto, 18914653Sdougm sectype); 18924653Sdougm ret = sa_delete_pgroup(handle, 18934653Sdougm propstring); 18944653Sdougm } else { 18954653Sdougm ret = SA_NO_MEMORY; 18964653Sdougm } 18974653Sdougm if (proto != NULL) 18984653Sdougm sa_free_attr_string(proto); 18994653Sdougm if (sectype != NULL) 19004653Sdougm sa_free_attr_string(sectype); 19013034Sdougm } 19023034Sdougm } 19033034Sdougm } 19044653Sdougm out: 19053034Sdougm if (groupname != NULL) 19064653Sdougm sa_free_attr_string(groupname); 19073034Sdougm if (shareid != NULL) 19084653Sdougm sa_free_attr_string(shareid); 19093034Sdougm if (propstring != NULL) 19104653Sdougm free(propstring); 19113034Sdougm 19123034Sdougm return (ret); 19133034Sdougm } 1914